quakespasm-0.91.0/0000755000000000000000000000000012646150016012452 5ustar rootrootquakespasm-0.91.0/LICENSE.txt0000644000000000000000000004325412407555166014317 0ustar rootroot 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. quakespasm-0.91.0/Linux/0000755000000000000000000000000012646150016013551 5ustar rootrootquakespasm-0.91.0/Linux/sgml/0000755000000000000000000000000012646150016014513 5ustar rootrootquakespasm-0.91.0/Linux/sgml/sgml2rawtxt0000755000000000000000000000015212257116274016743 0ustar rootroot#!/bin/bash sgml2txt -b 2 "$1" cat "$1.txt" | sed -e 's/[^m]*m//g' -e 's/.//g' >tmp$$ mv tmp$$ "$1.txt" quakespasm-0.91.0/Linux/sgml/Quakespasm.sgml0000644000000000000000000005447212646136302017527 0ustar rootroot
QuakeSpasm <toc> <verb></verb> <em>Page last edited: December 2015</em> <sect> About <p> <url url="http://quakespasm.sourceforge.net" name="QuakeSpasm"> is a Quake 1 engine based on the SDL port of <url url="http://www.celephais.net/fitzquake" name="FitzQuake">. </p><p> It includes support for 64 bit CPUs and custom music playback, and includes a new sound driver, some graphical niceities, and numerous bug-fixes and other improvements. <sect> Downloads <p> <itemize> <item><url url="http://quakespasm.sourceforge.net/download.htm" name="Project Downloads"> <item><url url="http://quakespasm.ericwa.com/job/quakespasm-sdl2/" name="Automatic Builds"> </itemize> <sect> Hints <p> <em>Visit the <url url="http://www.celephais.net/fitzquake" name="FitzQuake homepage"> for a full run-down of the engine's commands and variables.</em> <itemize> <item>To disable some changes, use "<bf>quakespasm -fitz</bf>" <item>Quakespasm's custom data is stored in "quakespasm.pak". Install this file alongside your id1 directory to enable the custom console background and other minor features. <item>For different sound drivers use "<bf>SDL_AUDIODRIVER=</bf><em>DRIVER</em><bf> ./quakespasm</bf>" , where DRIVER may be alsa, dsp, pulse, esd ... <item><bf>Shift+Escape</bf> draws the Console. <item>From the console, use <bf>UP</bf> to browse the command line history and <bf>TAB</bf> to autocomplete command and map names. <item>There is currently no CD Music volume support and SDL2 doesn't support CD audio. cd_sdl.c needs replacing with cd_linux.c, cd_bsd.c etc.. <item>In windows, alternative CD drives are accessible by "<bf>quakespasm -cddev F</bf>" (for example) <item>Quakespasm allows loading new games (mods) on the fly with "<bf>game</bf> <em>GAMENAME {-quoth/hipnotic/rogue}</em>" <item>Use "<bf>quakespasm -condebug</bf>" to save console log to "qconsole.log". SDL2 builds no longer generate stdout.txt/stderr.txt. </itemize> </p> <sect1>Music Playback<p> Quakespasm can play various external music formats, including MP3, OGG and FLAC. <itemize> <item>Tracks should be named like "track02.ogg", "track03.ogg" ... (there is no track01) and placed into "Quake/id1/music". <item>Unix users may need some extra libraries installed: "libmad" or "libmpg123" for MP3, and "libogg" and "libvorbis" for OGG. <item>As of 0.90.0, music is played back at 44100 Hz by default with no need to adjust "-sndspeed". <item>Use the "-noextmusic" option to disable this feature. <item>See <url url="Quakespasm-Music.txt"> for more details. </itemize> <sect> Compiling and Installation<p> <p>Quakespasm's (optional) custom data is now stored in the file <bf>quakespasm.pak</bf>. This file should be placed alongside your quakespasm binary and <bf>id1</bf> directory.</p> <p><em>To check-out the latest version of QuakeSpasm, use</em> <bf>svn co svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm</bf></p> <sect1> Linux/Unix <p> After extracting the source tarball, browse the Makefile and edit the music streaming options, then <code> make cp quakespasm /usr/local/games/quake (for example) </code> <newline> Compile time options include <itemize> <item><bf>make DO_USERDIRS=1</bf> to include user directories support <item><bf>make DEBUG=1</bf> for debugging <item><bf>make SDL_CONFIG=</bf><em>/PATH/TO/SDL-CONFIG</em> for unusual SDL installations <item><bf>make USE_SDL2=1</bf> to compile against SDL2 instead of SDL-1.2 </itemize> <p>Streaming music playback requires "libmad" or "libmpg123" for MP3, and "libogg" and "libvorbis" for OGG files. <p>The project can also be built with Codeblocks (project files included).</p> <sect1> Windows <p> The QuakeSpasm developers cross-compile windows binaries using <url url="http://www.mingw.org" name="MinGW"> and <url url="http://mingw-w64.sf.net" name="Mingw-w64">. The project can also be built using Visual Studio 2005 (or newer).</p> <sect1> Mac OS X <p> A Quakespasm App (including program launcher and update framework) can be made using the <bf>Xcode</bf> template found in the MacOSX directory. Alternatively, have a look at <bf>Makefile.darwin</bf> for more instructions on building from a console. </p> <sect> Known Bugs <p> Brightness issues should be fixed with GLSL gamma in 0.90.1, if your system supports OpenGL 2. For reference on older systems: <newline> Some versions of Xorg and SDL have brightness issues. <newline> Try setting "export SDL_VIDEO_X11_NODIRECTCOLOR=1", or if you have Xorg >= 7.5 and broken brightness, these patched libSDL binaries may help. <itemize> <item><url url="http://sourceforge.net/projects/quakespasm/files/Support%20Files/libSDL_gamma_patched.tgz/download" name="Gamma patched libSDL (i686-linux)"></li> <item><url url="http://sourceforge.net/projects/quakespasm/files/Support%20Files/libSDL_gamma_patched-AMD64.tgz/download" name="Gamma patched libSDL (x86_64-linux)"> </itemize> <p> The "game" command doesn't execute quake.rc in the new game directory being switched to. This means any custom key bindings in a mod's config.cfg or special settings in a quake.rc won't be loaded. The only workaround is launching the engine with the -game command-line switch instead of using the game console command. Or, after running the game command, you can run "exec quake.rc" by yourself (YMMV). </p> <sect> Changes<p> <sect1> Changes in 0.91.1<p> <sect2> Bugfixes <itemize> <item> Fix unwanted fog mode change upon video restart. <item> Work around Intel 855 bug in status bar drawing with "r_oldwater 0" and "scr_sbaralpha 0". <item> Fix an obscure GLSL bug where changing gamma would result in the screen turning to noise. <item> Fix GLSL gamma causing the tiled screen border to turn white when "sizedown" is used. <item> Fix an alias model VBO renderer bug where a model not precached during map start wouldn't be drawn. <item> Fix the order of OpenGL context creation and window creation in SDL2 video. <item> Fix a calling convention issue in windows DPI awareness function pointers. <item> Fix a random texture recoloring after video mode change. <item> Fix a liquid turning to garbage after several video mode changes and "r_oldwater 0". <item> Fix a wrong alpha-sorting bug introduced in 0.90.1. <item> Fix "flush" command not reloading mdl's from disk (bug introduced in 0.90.1). <item> Prevent a possible buffer overflow in Cbuf_Execute (old Q1/Q2 bug). <item> Prevent a possible vulnerability in MSG_ReadString (old Q1/Q2 bug). </itemize> <sect2> Visual improvements <itemize> <item> New cvars r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ/RMQEngine, non-archived, default to 0), and new worldspawn keys _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm, similar to the behaviour of the "fog" worldspawn key). <item> GLSL gamma is now supported on older hardware without NPOT extension. </itemize> <sect2> Interface improvements <itemize> <item> New r_pos command to show player position. <item> NaN detection in traceline with "developer 1" set now warns instead of errors. </itemize> <sect2> Code cleanup / Other <itemize> <item> Update third-party libraries. </itemize> <sect2> Raised limits <itemize> <item> Default max_edicts 8192 (was 2048) and no longer saved to config.cfg. <item> Default heapsize 256 MB (was 64 MB). <item> Default zone 4 MB (was 384 KB). <item> Raised MAX_SFX to 1024 (was 512). </itemize> </p> <sect1> Changes in 0.90.1<p> <sect2> Bugfixes <itemize> <item> Fix dynamic light artifact where changing lightmap are rendered one frame late (bug introduced in 0.90.0). <item> Fix texture memory leak when changing video modes with SDL2. <item> Fix rare incorrect mdl lighting on 64-bit builds. <url url="http://forums.insideqc.com/viewtopic.php?f=3&t=5620" name="(details here.)"> <item> Fix fullbrights turning black after "kill" command (bug introduced in 0.90.0). <item> Clear all fog values on map change to prevent colored fog carrying over to jam3_tronyn.bsp. <item> Allow loading saves with } character in quoted strings, fixes issue with retrojam1_skacky.bsp. <item> Fix viewmodel not lerping on extended-limit maps. <item> Fix crash on out-of-bounds skin number. </itemize> <sect2> Performance <itemize> <item> Use multithreaded OpenGL on OS X for better performance. <item> New, faster mdl renderer using GLSL. Disable with "-noglslalias". </itemize> <sect2> Visual improvements <itemize> <item> New gamma correction implementation using GLSL. Fixes all known gamma issues (affecting the full display, persisting after quitting, or darkening the screen on OS X). Disable with "-noglslgamma". <item> Use high-quality water by default (r_oldwater 0). <item> Shadows use stencil buffer to avoid overlapping artifacts (from MarkV.) <item> r_noshadow_list cvar added (from MarkV.) </itemize> <sect2> Interface improvements <itemize> <item> Support pausing demo playback with the "pause" command. <item> Autocompletion for "game", "record", "playdemo". <item> Experimental windowed fullscreen mode available with vid_desktopfullscreen 1 (only in SDL2 builds, takes effect upon entering fullscreen mode the next time.) <item> Silence "exceeded standard limit" messages unless developer cvar is >= 1. <item> Some spam moved from developer 1 to 2: "can't find tga/lit/ent", "trying to load ent", "bad chunk length", "meshing", "PR_AlocStringSlots: realloc'ing" </itemize> <sect2> Code cleanup <itemize> <item> Clean up IDE project files to build on fresh systems. <item> Update 3rd-party libraries. </itemize> </p> <sect1> Changes in 0.90.0<p> <itemize> <item> Fix issues on Windows systems with DPI scaling.</item> <item> Unix/Mac user directories support. Disabled by default, 'make DO_USERDIRS=1' to enable it. <item> SDL2 support. Disabled by default, 'make USE_SDL2=1' to enable it. <item> Revised keyboard input code. <item> Revised/improved the 'game' command, i.e. on-the-fly mod changing. It now accepts an optional second argument for mission packs or quoth support i.e. -hipnotic, -rogue, or -quoth. For example, for WarpSpasm: "game warp -quoth" <item> Command line: "-game {quoth/hipnotic/rogue}" is now treated the same as -quoth, -hipnotic, or -rogue. <item> Console speed now resolution-independent. <item> Disabled gl_zfix, which caused glitches and is undesirable for new maps. Replacement .ent files to fix z-fighting for several id1 maps added to quakespasm.pak. <item> PF_VarString buffer bumped to 1024, avoids truncated centerprints from the 'In The Shadows' mod. <item> Support for opengl non-power-of-two-textures extension (disable with command line: "-notexturenpot".) <item> Support for OpenGL vertex buffer objects (VBO, OpenGL 1.5 or newer) for world and brush models (disable with command line: "-novbo".) <item> Antialiasing (FSAA) support (command line: -fsaa x, where x can be 0, 2, 4, 8). <item> Fence textures support. <item> Dynamic light speedup. Speedup loading of tga and pcx external images. <item> Brush model drawing speedup. <item> Support for BSP2 and 2PSB map formats. <item> Support for Opus, FLAC, and tracker music (S3M, IT, UMX, etc.), as compile-time options. <item> Music and sfx now mixed at 44100 Hz to avoid downsampling music. Low-pass filter applied to the sfx if -sndspeed is 11025 (the default), to preserve the same sound quality as 0.85.9. New -mixspeed option sets the rate for mixing sfx and music, and output to the OS (default 44100), setting it to 11025 reverts to 0.85.9 behaviour. New snd_filterquality cvar, value can be between 1 (emulate OS X resampler) and 5 (emulate Windows resampler), controls the sound of the low-pass filter. <item> Better Hor+ field of view (FOV) scaling behavior. <item> Better cross-map demo playback support. <item> Fix screenshots when screen width isn't a multiple of 4. <item> Fix a lighting glitch due to floating point precision. <item> Fix a looping sounds glitch. <item> Fix a vulnerability in file extension handling. Tighten path handling safety. <item> Initialize opengl with 24-bit depth buffer at 32 bpp. <item> Reset all models upon gamedir changes. (Fixes failures with mods using custom content.) <item> Fix broken behavior upon gamedir changes if -basedir is specified on the command line. <item> NET_MAXMESSAGE and MAX_MSGLEN limits bumped to 64000. <item> MAX_EFRAGS bumped to 4096, and MAX_CHANNELS to 1024. <item> MAX_ENT_LEAFS bumped from 16 to 32 to work around disappearing or flickering brush models in some situations. Also, if an entity is visible from MAX_ENT_LEAFS or more leafs, we now always send it to the client. <item> Fix cvar cycle command not working sometimes. <item> Host_Error upon missing models. (Prevents segmentation faults.) <item> Change sv_aim default value to 1 (i.e. turn off autoaim) <item> Add 'prev' and 'next' keywords to the 'cd' command. <item> Work around a linux cdrom issue (playback might not start for a while after a stop). <item> Quakespasm content customization moved from engine-embedded into a new optional quakespasm.pak file. <item> Version bumped to 0.90.0 (because Quakespasm has a decent life of it's own) <item> Other fixes and clean-ups. </itemize> </p> <sect1> Changes in 0.85.9<p> <itemize> <item> Fixes for several undefined behaviors in C code (gcc-4.8 support.) <item> Implemented Hor+ style field of view (FOV) scaling, useful for widescreen resolutions. Configured by new cvar fov_adapt: set it to 1 and your fov will be scaled automatically according to the resolution. Enabled by default. <item> Adjusted string buffers for PR_ValueString and friends to fix crashes with excessively long global strings seen in some rude mods. <item> Toned down warning messages from PF_VarString() a bit. <item> Fixed Fitzquake's map existence check in changelevel (used to leak file handles which would end up in a Sys_Error() due to consuming all free handles if many maps reside not in pak files.) <item> Fixes/cleanups in chat mode handling. Client no longer gets stuck in chat mode upon disconnect. <item> Mouse grab/key_dest fixes and key cleanups. <item> The "speedkey" now acts as "slowkey" when "always run" is on. <item> Support for demo recording after connection to server. (thanks to Baker for a patch) <item> Corner case fixes in COM_Parse() for quoted strings and support for C-style /*..*/ comments. <item> Changed lightmaps to GL_RGBA instead of GL_RGB. <item> Better parse for opengl extensions list (from quakeforge.) <item> Vsync saving/loading fixes. <item> Fixed pointfile loading. <item> Multiple cleanups in gl_vidsdl.c. <item> Opus music decoding support (as an optional patch only.) <item> Several other minor fixes/cleanups. </itemize> </p> <sect1> Changes in 0.85.8<p> <itemize> <item> Made Quake shareware 1.00 and 1.01 versions to be recognized properly. <item> Fixed control-character handling in unicode mode. Keyboard input tweaks. <item> Made the keypad keys to send separate key events in game mode. <item> Text pasting support from OS clipboard to console. (windows and macosx.) <item> Support for the Apple (Command) key on macosx. <item> Fixed increased (more than 32) dynamic lights. <item> Music playback: Made sure that the file's channels count is supported. <item> Support for Solaris. <item> Switched to using libmad instead of libmpg123 for MP3 playback on Mac OS X. <item> Better support for building the Mac OS X version using a makefile, support for cross-compiling on Linux. <item> Fixed a minor intermissions glitch. <item> Increased string buffer size from 256 to 384 for PF_VarString to work around broken mods such as UQC. <item> Restored original behavior for Quake registered version detection. <item> Minor demo recording/playback tweaks. <item> Minor tweaks to the scale menu option. <item> unbindall before loading stored bindings (configurable by new cvar cfg_unbindall, enabled by default.) <item> New icon. <item> Miscellaneous source code cleanups. </itemize> </p> <sect1> Changes in 0.85.7<p> <itemize> <item> Added support for cross-level demo playback <item> gl_texturemode is reimplemented as a cvar with a callback and the setting is automatically saved to the config <item> Fixed execution of external files without a newline at the end <item> Reduced memory usage during reloading of textures <item> Fixed compilation on GNU/kFreeBSD (Debian bug #657793) <item> Fixed backspace key on Mac OS X <item> Disable mouse acceleration in Mac OS X <item> Worked around recursive calling of the anisotropic filter callback <item> Console word wrap and long input line fixes <item> Verified correct compilation by clang (using v3.0) <item> Several other small changes mostly invisible to the end-user </itemize> </p> <sect1> Changes in 0.85.6<p> <itemize> <item> More work for string buffer safety <item> Reverted v0.85.5 change of not allowing deathmatch and coop cvars to be set at the same time (was reported for possibility of causing compatibility issues with mods) <item> Several cleanups/changes in the cvar layer <item> Minor SDL video fixes. </itemize> </p> <sect1> Changes in 0.85.5<p> <itemize> <item> SDL input driver updated adding native keymap and dead key support to the console <item> Fixed a crash in net play in maps with extended limits <item> Verified successful compilation using gcc-4.6.x <item> Added workaround against GL texture flicker (z fighting), controlled by new cvar 'gl_zfix' <item> Read video variables early so that a vid_restart isn't necessary after init <item> mlook and lookspring fixes <item> Added support for loading external entity files, controlled by new cvar 'external_ents' <item> Made mp3 playback to allocate system memory instead of zone <item> Some updates to the progs interpreter code <item> Fixed r_nolerp_list parsing code of fitzquake <item> Made sure that deathmatch and coop are not set at the same time <item> Several code updates from uHexen2 project, several code cleanups. </itemize> </p> <sect1> Changes in 0.85.4<p> <itemize> <item> Implement music (OGG, MP3, WAV) playback <item> A better fix for the infamous SV_TouchLinks problem, no more hard lockups with maps such as "whiteroom" <item> Add support for mouse buttons 4 and 5 <item> Fix the "unalias" console command <item> Restore the "screen size" menu item <item> Fixed an erroneous protocol check in the server code <item> Raised the default zone memory size to 384 kb <item> Raised the default max_edicts from 1024 to 2048 <item> Revised lit file loading, the lit file must be from the same game directory as the map itself or from a searchpath with a higher priority <item> Fixed rest of the compiler warnings <item> Other minor sound and cdaudio updates </itemize> </p> <sect1> Changes in 0.85.3<p> <itemize> <item> Fix the "-dedicated" option (thanks Oz) and add platform specific networking code (default) rather than SDL_net <item> Much needed OSX framework stuff from Kristian <item> Add a persistent history feature (thanks Baker) <item> Add a slider for scr_sbaralpha, which now defaults to 0.95 (slightly transparent, allowing for a nicer status bar) <item> Allow player messages longer than 32 characters <item> Sockaddr fix for FreeBSD/OSX/etc networking <item> Connect status bar size to the scale slider <item> Include an ISNAN (is not-a-number) fix to catch the occassional quake C bug giving traceline problems <item> Enumerate options menus <item> Add a "prev weapon" menu item (from Sander) <item> Small fix to Sound Block/Unblock on win32 <item> Lots of code fixes (some from uhexen2) <item> Sys_Error calls Host_Shutdown <item> Added MS Visual Studio support <item> Add a "-cd" option to let the CD Player work in dedicated mode, and some other CD tweaks. </itemize> <sect1> Changes in 0.85.2<p> <itemize> <item> Replace the old "Screen size" slider with a "Scale" slider <item> Don't constantly open and close condebug log <item> Heap of C clean-ups <item> Fix mapname sorting <item> Alias the "mods" command to "games" <item> Block/Unblock sound upon focus loss/gain <item> NAT fix (networking protocol fix) <item> SDLNet_ResolveHost bug-fix allowing connection to ports other than 26000 <item> Bumped array size of sv_main.c::localmodels from 5 to 6 fixing an old fitzquake-0.85 bug which used to cause segfaults depending on the compiler. <item> Accept commandline options like "+connect ip:port" <item> Add OSX Makefile (tested?) </itemize> <sect1> Changes in 0.85.1<p> <itemize> <item>64 bit CPU support <item>Restructured SDL sound driver <item>Custom conback <item>Tweaked the command line completion and added a map/changelevel autocompletion function <item>Alt+Enter toggles fullscreen <item>Disable Draw_BeginDisc which causes core dumps when called excessively <item>Show helpful info on start-up <item>Include real map name (sv.name) and skill in the status bar <item>Remove confirm quit dialog <item>Don't spam the console with PackFile seek requests <item>Default to window mode <item>Withdraw console when playing demos <item>Don't play demos on program init <item>Default Heapsize is 64meg <item>Changes to default console alpha, speed <item>Changes to cvar persistence gl_flashblend (default 0), r_shadow, r_wateralpha, r_dynamic, r_novis </itemize> <sect> Todo <p> <itemize> <item>Add uHexen2's first person camera (and menu item) <item>Native CD audio support (if desired). cd_sdl.c doesn't have proper volume controls and SDL2 doesn't support CD audio </itemize> <sect> Copyright <p> <itemize> <item>Quake and Quakespasm are released under the <url url="http://www.gnu.org/licenses/gpl-2.0.html" name="GNU GENERAL PUBLIC LICENSE Version 2"> <item>Quakespasm console background image by <bf>AAS</bf>, released under the <url url="http://creativecommons.org/licenses/by/3.0/legalcode" name="CREATIVE COMMONS PUBLIC LICENSE"> </itemize> <sect> Contact <p> <itemize> <item><url url="http://sourceforge.net/projects/quakespasm" name="QuakeSpasm Project page"> <item><url url="http://sourceforge.net/p/quakespasm/bugs/?source=navbar" name="Bug reports"> <item><url url="mailto:gmail - dot - com - username - sezeroz" name="Ozkan"> (project leader), <url url="mailto:gmail - dot - com - username - ewasylishen" name="Eric">, <url url="mailto:gmail - dot - com - username - a.h.vandijk" name="Sander">, <url url="mailto:yahoo - dot - com - username - stevenaaus" name="Stevenaaus"> </itemize> <sect> Links <p> <itemize> <item><url url="http://quakespasm.sourceforge.net" name="QuakeSpasm Homepage"> <item><url url="http://quakespasm.sourceforge.net/download.htm" name="Downloads"> <item><url url="http://www.celephais.net/fitzquake" name="FitzQuake Homepage"> <item><url url="http://www.celephais.net/board/view_thread.php?id=60452" name="Func Quakespasm forum"> <item><url url="http://forums.insideqc.com" name="Inside3D forums"> </itemize> </article> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Linux/sgml/Makefile.sgml����������������������������������������������������������0000644�0000000�0000000�00000000266�12403446630�017121� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# sgml tools are from linuxdoc-tools default: Quakespasm.sgml sgml2html -s 0 -T 2 Quakespasm.sgml 2>/dev/null all: default text text txt: Quakespasm.sgml ./sgml2rawtxt Quakespasm ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Linux/CodeBlocks/�����������������������������������������������������������������0000755�0000000�0000000�00000000000�12646150016�015561� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Linux/CodeBlocks/QuakeSpasm.cbp���������������������������������������������������0000644�0000000�0000000�00000024316�12327137640�020333� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <CodeBlocks_project_file> <FileVersion major="1" minor="6" /> <Project> <Option title="QuakeSpasm" /> <Option pch_mode="2" /> <Option compiler="gcc" /> <Build> <Target title="Debug"> <Option output="bin/Debug/quakespasm" prefix_auto="1" extension_auto="1" /> <Option object_output="obj/Debug/" /> <Option type="1" /> <Option compiler="gcc" /> <Option parameters="-window -basedir /home/kristian/Desktop/Quake -sndspeed 48000" /> <Compiler> <Add option="-g" /> </Compiler> </Target> <Target title="Release"> <Option output="bin/Release/quakespasm" prefix_auto="1" extension_auto="1" /> <Option object_output="obj/Release/" /> <Option type="0" /> <Option compiler="gcc" /> <Option parameters="-window -basedir /home/kristian/Desktop/Quake -sndspeed 48000" /> <Compiler> <Add option="-O2" /> </Compiler> <Linker> <Add option="-s" /> </Linker> </Target> </Build> <Compiler> <Add option="-Wall" /> <Add option="`sdl-config --cflags`" /> <Add option="-DUSE_CODEC_MP3" /> <Add option="-DUSE_CODEC_VORBIS" /> <Add option="-DUSE_CODEC_WAVE" /> </Compiler> <Linker> <Add option="`sdl-config --libs`" /> <Add option="-lGL" /> <Add option="-lvorbisfile" /> <Add option="-lvorbis" /> <Add option="-logg" /> <Add option="-lmad" /> </Linker> <Unit filename="../../Quake/anorm_dots.h" /> <Unit filename="../../Quake/anorms.h" /> <Unit filename="../../Quake/arch_def.h" /> <Unit filename="../../Quake/bgmusic.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/bgmusic.h" /> <Unit filename="../../Quake/bspfile.h" /> <Unit filename="../../Quake/cd_sdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cdaudio.h" /> <Unit filename="../../Quake/cfgfile.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cfgfile.h" /> <Unit filename="../../Quake/chase.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_demo.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_input.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_main.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_parse.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_tent.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/client.h" /> <Unit filename="../../Quake/cmd.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cmd.h" /> <Unit filename="../../Quake/common.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/common.h" /> <Unit filename="../../Quake/console.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/console.h" /> <Unit filename="../../Quake/crc.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/crc.h" /> <Unit filename="../../Quake/cvar.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cvar.h" /> <Unit filename="../../Quake/draw.h" /> <Unit filename="../../Quake/gl_draw.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_fog.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_mesh.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_model.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_model.h" /> <Unit filename="../../Quake/gl_refrag.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_rlight.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_rmain.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_rmisc.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_screen.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_sky.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_texmgr.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_texmgr.h" /> <Unit filename="../../Quake/gl_vidsdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_warp.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_warp_sin.h" /> <Unit filename="../../Quake/glquake.h" /> <Unit filename="../../Quake/host.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/host_cmd.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/image.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/image.h" /> <Unit filename="../../Quake/in_sdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/input.h" /> <Unit filename="../../Quake/keys.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/keys.h" /> <Unit filename="../../Quake/main_sdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/mathlib.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/mathlib.h" /> <Unit filename="../../Quake/menu.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/menu.h" /> <Unit filename="../../Quake/modelgen.h" /> <Unit filename="../../Quake/net.h" /> <Unit filename="../../Quake/net_bsd.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_defs.h" /> <Unit filename="../../Quake/net_dgrm.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_dgrm.h" /> <Unit filename="../../Quake/net_loop.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_loop.h" /> <Unit filename="../../Quake/net_main.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_sys.h" /> <Unit filename="../../Quake/net_udp.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_udp.h" /> <Unit filename="../../Quake/pl_linux.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/platform.h" /> <Unit filename="../../Quake/pr_cmds.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/pr_comp.h" /> <Unit filename="../../Quake/pr_edict.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/pr_exec.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/progdefs.h" /> <Unit filename="../../Quake/progdefs.q1" /> <Unit filename="../../Quake/progs.h" /> <Unit filename="../../Quake/protocol.h" /> <Unit filename="../../Quake/q_sound.h" /> <Unit filename="../../Quake/q_stdinc.h" /> <Unit filename="../../Quake/qs_bmp.h" /> <Unit filename="../../Quake/quakedef.h" /> <Unit filename="../../Quake/r_alias.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/r_brush.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/r_part.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/r_sprite.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/r_world.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/render.h" /> <Unit filename="../../Quake/resource.h" /> <Unit filename="../../Quake/sbar.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sbar.h" /> <Unit filename="../../Quake/screen.h" /> <Unit filename="../../Quake/server.h" /> <Unit filename="../../Quake/snd_codec.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_codec.h" /> <Unit filename="../../Quake/snd_codeci.h" /> <Unit filename="../../Quake/snd_dma.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_flac.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_flac.h" /> <Unit filename="../../Quake/snd_mem.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_mikmod.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_mikmod.h" /> <Unit filename="../../Quake/snd_mix.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_modplug.c"> <Unit filename="../../Quake/snd_modplug.h" /> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_mp3.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_mp3.h" /> <Unit filename="../../Quake/snd_opus.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_opus.h" /> <Unit filename="../../Quake/snd_sdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_umx.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_umx.h" /> <Unit filename="../../Quake/snd_vorbis.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_vorbis.h" /> <Unit filename="../../Quake/snd_wave.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_wave.h" /> <Unit filename="../../Quake/spritegn.h" /> <Unit filename="../../Quake/strl_fn.h" /> <Unit filename="../../Quake/strlcat.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/strlcpy.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sv_main.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sv_move.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sv_phys.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sv_user.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sys.h" /> <Unit filename="../../Quake/sys_sdl_unix.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/vid.h" /> <Unit filename="../../Quake/view.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/view.h" /> <Unit filename="../../Quake/wad.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/wad.h" /> <Unit filename="../../Quake/world.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/world.h" /> <Unit filename="../../Quake/zone.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/zone.h" /> <Extensions> <code_completion /> <envvars /> <debugger /> </Extensions> </Project> </CodeBlocks_project_file> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Linux/CodeBlocks/QuakeSpasm-SDL2.cbp����������������������������������������������0000644�0000000�0000000�00000024410�12416530135�021023� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <CodeBlocks_project_file> <FileVersion major="1" minor="6" /> <Project> <Option title="QuakeSpasm-SDL2" /> <Option pch_mode="2" /> <Option compiler="gcc" /> <Build> <Target title="Debug"> <Option output="bin/Debug/quakespasm-sdl2" prefix_auto="1" extension_auto="1" /> <Option object_output="obj/Debug/SDL2/" /> <Option type="1" /> <Option compiler="gcc" /> <Option parameters="-window -basedir /home/kristian/Desktop/Quake -sndspeed 48000" /> <Compiler> <Add option="-g" /> </Compiler> </Target> <Target title="Release"> <Option output="bin/Release/quakespasm-sdl2" prefix_auto="1" extension_auto="1" /> <Option object_output="obj/Release/SDL2/" /> <Option type="0" /> <Option compiler="gcc" /> <Option parameters="-window -basedir /home/kristian/Desktop/Quake -sndspeed 48000" /> <Compiler> <Add option="-O2" /> </Compiler> <Linker> <Add option="-s" /> </Linker> </Target> </Build> <Compiler> <Add option="-Wall" /> <Add option="`sdl2-config --cflags`" /> <Add option="-DUSE_SDL2" /> <Add option="-DUSE_CODEC_MP3" /> <Add option="-DUSE_CODEC_VORBIS" /> <Add option="-DUSE_CODEC_WAVE" /> </Compiler> <Linker> <Add option="`sdl2-config --libs`" /> <Add option="-lGL" /> <Add option="-lvorbisfile" /> <Add option="-lvorbis" /> <Add option="-logg" /> <Add option="-lmad" /> </Linker> <Unit filename="../../Quake/anorm_dots.h" /> <Unit filename="../../Quake/anorms.h" /> <Unit filename="../../Quake/arch_def.h" /> <Unit filename="../../Quake/bgmusic.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/bgmusic.h" /> <Unit filename="../../Quake/bspfile.h" /> <Unit filename="../../Quake/cd_sdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cdaudio.h" /> <Unit filename="../../Quake/cfgfile.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cfgfile.h" /> <Unit filename="../../Quake/chase.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_demo.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_input.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_main.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_parse.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cl_tent.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/client.h" /> <Unit filename="../../Quake/cmd.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cmd.h" /> <Unit filename="../../Quake/common.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/common.h" /> <Unit filename="../../Quake/console.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/console.h" /> <Unit filename="../../Quake/crc.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/crc.h" /> <Unit filename="../../Quake/cvar.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/cvar.h" /> <Unit filename="../../Quake/draw.h" /> <Unit filename="../../Quake/gl_draw.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_fog.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_mesh.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_model.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_model.h" /> <Unit filename="../../Quake/gl_refrag.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_rlight.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_rmain.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_rmisc.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_screen.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_sky.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_texmgr.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_texmgr.h" /> <Unit filename="../../Quake/gl_vidsdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_warp.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/gl_warp_sin.h" /> <Unit filename="../../Quake/glquake.h" /> <Unit filename="../../Quake/host.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/host_cmd.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/image.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/image.h" /> <Unit filename="../../Quake/in_sdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/input.h" /> <Unit filename="../../Quake/keys.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/keys.h" /> <Unit filename="../../Quake/main_sdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/mathlib.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/mathlib.h" /> <Unit filename="../../Quake/menu.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/menu.h" /> <Unit filename="../../Quake/modelgen.h" /> <Unit filename="../../Quake/net.h" /> <Unit filename="../../Quake/net_bsd.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_defs.h" /> <Unit filename="../../Quake/net_dgrm.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_dgrm.h" /> <Unit filename="../../Quake/net_loop.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_loop.h" /> <Unit filename="../../Quake/net_main.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_sys.h" /> <Unit filename="../../Quake/net_udp.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/net_udp.h" /> <Unit filename="../../Quake/pl_linux.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/platform.h" /> <Unit filename="../../Quake/pr_cmds.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/pr_comp.h" /> <Unit filename="../../Quake/pr_edict.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/pr_exec.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/progdefs.h" /> <Unit filename="../../Quake/progdefs.q1" /> <Unit filename="../../Quake/progs.h" /> <Unit filename="../../Quake/protocol.h" /> <Unit filename="../../Quake/q_sound.h" /> <Unit filename="../../Quake/q_stdinc.h" /> <Unit filename="../../Quake/qs_bmp.h" /> <Unit filename="../../Quake/quakedef.h" /> <Unit filename="../../Quake/r_alias.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/r_brush.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/r_part.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/r_sprite.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/r_world.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/render.h" /> <Unit filename="../../Quake/resource.h" /> <Unit filename="../../Quake/sbar.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sbar.h" /> <Unit filename="../../Quake/screen.h" /> <Unit filename="../../Quake/server.h" /> <Unit filename="../../Quake/snd_codec.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_codec.h" /> <Unit filename="../../Quake/snd_codeci.h" /> <Unit filename="../../Quake/snd_dma.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_flac.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_flac.h" /> <Unit filename="../../Quake/snd_mem.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_mikmod.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_mikmod.h" /> <Unit filename="../../Quake/snd_mix.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_modplug.c"> <Unit filename="../../Quake/snd_modplug.h" /> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_mp3.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_mp3.h" /> <Unit filename="../../Quake/snd_opus.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_opus.h" /> <Unit filename="../../Quake/snd_sdl.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_umx.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_umx.h" /> <Unit filename="../../Quake/snd_vorbis.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_vorbis.h" /> <Unit filename="../../Quake/snd_wave.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/snd_wave.h" /> <Unit filename="../../Quake/spritegn.h" /> <Unit filename="../../Quake/strl_fn.h" /> <Unit filename="../../Quake/strlcat.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/strlcpy.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sv_main.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sv_move.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sv_phys.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sv_user.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/sys.h" /> <Unit filename="../../Quake/sys_sdl_unix.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/vid.h" /> <Unit filename="../../Quake/view.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/view.h" /> <Unit filename="../../Quake/wad.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/wad.h" /> <Unit filename="../../Quake/world.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/world.h" /> <Unit filename="../../Quake/zone.c"> <Option compilerVar="CC" /> </Unit> <Unit filename="../../Quake/zone.h" /> <Extensions> <code_completion /> <envvars /> <debugger /> </Extensions> </Project> </CodeBlocks_project_file> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/�����������������������������������������������������������������������������0000755�0000000�0000000�00000000000�12646150016�013345� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/����������������������������������������������������������������������0000755�0000000�0000000�00000000000�12646150016�014623� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/�����������������������������������������������������������������0000755�0000000�0000000�00000000000�12646150016�015563� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e2m2.ent���������������������������������������������������������0000644�0000000�0000000�00000065053�12425501423�017046� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "message" "the Ogre Citadel" "sounds" "8" "wad" "gfx/wizard.wad" "classname" "worldspawn" "worldtype" "0" } { "origin" "160 -160 120" "classname" "light" } { "angle" "90" "origin" "-256 -1952 280" "classname" "info_player_start" } { "classname" "light" "origin" "160 -392 248" "light" "200" } { "classname" "light" "origin" "160 -648 184" } { "classname" "light" "origin" "-56 -392 248" "light" "200" } { "classname" "light" "origin" "376 -392 248" "light" "200" } { "classname" "light" "origin" "288 -416 -72" "light" "200" } { "classname" "light" "origin" "32 -416 -72" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "10 -270 148" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "314 -270 148" "light" "250" } { "classname" "light" "origin" "-264 -440 248" "light" "200" } { "classname" "light" "origin" "584 -440 248" "light" "200" } { "classname" "light" "origin" "544 -648 248" } { "light" "150" "origin" "648 -456 -184" "classname" "light" } { "origin" "376 -800 184" "classname" "light" } { "classname" "light" "origin" "-152 -752 184" "light" "250" } { "classname" "light" "origin" "-232 -592 184" "light" "250" } { "classname" "light" "origin" "160 112 184" } { "classname" "light" "origin" "160 352 120" } { "classname" "light" "origin" "160 216 -48" "light" "120" } { "classname" "light" "origin" "160 16 -48" "light" "120" } { "classname" "light" "origin" "160 544 144" "light" "225" } { "classname" "light" "origin" "480 576 88" } { "classname" "light" "origin" "480 448 88" } { "classname" "light" "origin" "480 576 168" "light" "250" } { "classname" "light" "origin" "480 448 168" "light" "250" } { "classname" "light" "origin" "160 896 312" "light" "350" } { "classname" "light" "origin" "288 896 312" "light" "100" } { "classname" "light" "origin" "32 896 312" "light" "100" } { "classname" "light" "origin" "160 1008 312" "light" "100" } { "classname" "light" "origin" "160 784 312" "light" "100" } { "classname" "light" "origin" "392 120 184" "light" "350" } { "classname" "light" "origin" "568 208 184" "light" "350" } { "classname" "light" "origin" "720 480 184" } { "classname" "light" "origin" "640 632 184" } { "classname" "light" "origin" "472 1152 56" } { "classname" "light" "origin" "512 896 152" } { "origin" "800 800 184" "classname" "light" } { "light" "200" "origin" "632 1264 -40" "classname" "light" } { "origin" "800 1032 184" "classname" "light" } { "origin" "760 1472 64" "classname" "light" } { "light" "200" "origin" "544 1416 56" "classname" "light" } { "origin" "672 1256 184" "classname" "light" "light" "200" } { "light" "200" "origin" "1024 1272 184" "classname" "light" } { "light" "200" "origin" "992 1440 184" "classname" "light" } { "origin" "1240 488 184" "classname" "light" } { "origin" "1280 136 176" "classname" "light" } { "origin" "160 1304 136" "classname" "light" } { "origin" "160 1648 256" "classname" "light" "light" "200" } { "origin" "240 1600 256" "classname" "light" "light" "200" } { "origin" "16 1616 168" "classname" "light" "light" "200" } { "light" "200" "origin" "-120 1304 40" "classname" "light" } { "origin" "-352 1144 16" "classname" "light" "light" "250" } { "origin" "-56 1096 64" "classname" "light" } { "light" "200" "origin" "-56 1152 280" "classname" "light" } { "light" "350" "origin" "-440 1144 200" "classname" "light" } { "light" "200" "origin" "-352 1336 -72" "classname" "light" } { "origin" "-488 368 56" "classname" "light" "light" "250" } { "light" "350" "origin" "-488 896 136" "classname" "light" } { "origin" "-216 896 184" "classname" "light" "light" "250" } { "origin" "-128 536 168" "classname" "light" "light" "200" } { "light" "150" "origin" "-104 480 32" "classname" "light" } { "light" "150" "origin" "-208 936 56" "classname" "light" } { "light" "150" "origin" "-208 736 32" "classname" "light" } { "origin" "-344 64 184" "classname" "light" } { "light" "350" "origin" "-648 384 184" "classname" "light" } { "light" "350" "origin" "-488 688 184" "classname" "light" } { "light" "150" "origin" "-680 496 -36" "classname" "light" } { "light" "350" "origin" "-600 1104 96" "classname" "light" } { "origin" "-824 896 168" "classname" "light" } { "origin" "-896 600 160" "classname" "light" } { "target" "t1" "classname" "trigger_teleport" "model" "*1" } { "spawnflags" "1792" "targetname" "t1" "origin" "-448 264 -56" "classname" "info_teleport_destination" "angle" "45" } { "light" "250" "origin" "-168 1320 160" "classname" "light" } { "origin" "-24 896 184" "classname" "light" } { "origin" "-104 896 184" "classname" "light" "light" "250" } { "spawnflags" "2" "origin" "-680 880 48" "classname" "item_health" } { "angle" "90" "origin" "-896 512 24" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "-184 560 128" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "160 1640 160" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "1272 112 80" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "176 -784 24" "classname" "info_player_deathmatch" } { "spawnflags" "1" "origin" "208 -160 0" "classname" "item_rockets" } { "origin" "64 464 0" "classname" "item_health" } { "origin" "120 464 0" "classname" "item_health" } { "spawnflags" "1" "origin" "-8 840 64" "classname" "item_health" } { "spawnflags" "1" "origin" "-8 952 64" "classname" "item_health" } { "spawnflags" "9" "origin" "568 880 0" "classname" "item_weapon" } { "origin" "456 1104 -88" "classname" "item_health" } { "spawnflags" "1" "origin" "664 1272 -88" "classname" "item_shells" } { "angle" "225" "origin" "888 1312 120" "classname" "info_player_deathmatch" } { "origin" "1328 168 56" "classname" "item_health" } { "origin" "1328 128 56" "classname" "item_health" } { "origin" "1328 208 56" "classname" "item_health" } { "spawnflags" "1" "origin" "816 1472 0" "classname" "item_shells" } { "light" "200" "origin" "-64 -120 -56" "classname" "light" } { "light" "200" "origin" "-296 -160 -56" "classname" "light" } { "light" "200" "origin" "-296 -208 -272" "classname" "light" } { "classname" "func_plat" "model" "*2" } { "spawnflags" "2" "origin" "-192 -176 -80" "classname" "item_health" } { "light" "350" "origin" "-816 128 184" "classname" "light" } { "light" "350" "origin" "-664 -80 184" "classname" "light" } { "light" "250" "origin" "-656 112 32" "classname" "light" } { "origin" "-352 208 56" "classname" "light" "light" "250" } { "origin" "-184 504 24" "classname" "light" "light" "250" } { "classname" "item_armor1" "origin" "400 -888 0" } { "spawnflags" "1792" "classname" "item_armorInv" "origin" "-104 448 104" } { "classname" "item_armor2" "origin" "-680 496 32" } { "classname" "weapon_grenadelauncher" "origin" "168 1608 136" "spawnflags" "1792" } { "classname" "weapon_rocketlauncher" "origin" "1232 176 56" "spawnflags" "1792" } { "classname" "weapon_supernailgun" "origin" "-960 944 40" "spawnflags" "1792" } { "classname" "weapon_supershotgun" "origin" "752 1464 0" "spawnflags" "1792" } { "classname" "weapon_nailgun" "origin" "160 120 24" "spawnflags" "1792" } { "classname" "item_rockets" "origin" "-224 792 104" "spawnflags" "1792" } { "classname" "item_rockets" "origin" "-640 120 -56" "spawnflags" "1792" } { "light" "200" "origin" "-70 -1126 212" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "186 -1134 148" } { "light" "200" "origin" "138 -966 100" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "-150 -1318 260" } { "light" "150" "origin" "184 -880 72" "classname" "light" } { "style" "6" "light" "200" "origin" "-46 -1742 340" "classname" "light_torch_small_walltorch" } { "style" "1" "light" "200" "classname" "light_torch_small_walltorch" "origin" "-486 -1726 340" } { "origin" "-272 -1544 384" "classname" "light" "light" "200" } { "style" "6" "light" "200" "classname" "light_torch_small_walltorch" "origin" "-414 -2006 340" } { "style" "1" "light" "200" "origin" "-134 -1958 340" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "-472 -1840 328" "classname" "light" } { "classname" "light" "origin" "-72 -1592 328" "light" "150" } { "light" "150" "origin" "-320 -1424 264" "classname" "light" } { "light" "150" "origin" "-256 -1952 280" "classname" "light" } { "light" "200" "classname" "light" "origin" "-272 -1720 312" } { "origin" "-232 -1280 168" "classname" "path_corner" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "-64 -1176 120" "targetname" "t6" "target" "t7" } { "origin" "152 -1104 56" "classname" "path_corner" "targetname" "t7" "target" "t8" } { "classname" "path_corner" "origin" "192 -952 8" "targetname" "t8" "target" "t9" } { "origin" "184 -808 8" "classname" "path_corner" "target" "t3" "targetname" "t9" } { "classname" "path_corner" "origin" "512 -776 8" "targetname" "t3" "target" "t10" } { "origin" "-200 -648 8" "classname" "path_corner" "targetname" "t4" "target" "t11" } { "classname" "monster_knight" "origin" "-360 -1616 232" "target" "t5" "angle" "90" } { "origin" "512 -648 8" "classname" "path_corner" "targetname" "t10" "target" "t4" } { "classname" "path_corner" "origin" "-200 -776 8" "targetname" "t11" "target" "t3" } { "classname" "monster_knight" "origin" "24 -632 24" "spawnflags" "256" "target" "t4" } { "classname" "monster_knight" "origin" "336 -752 24" "spawnflags" "256" "target" "t3" } { "classname" "monster_knight" "origin" "56 -712 24" "angle" "270" "spawnflags" "768" } { "spawnflags" "768" "angle" "270" "origin" "160 -712 24" "classname" "monster_knight" } { "classname" "monster_knight" "origin" "264 -712 24" "angle" "270" "spawnflags" "768" } { "classname" "item_health" "origin" "-432 -1640 208" "spawnflags" "1" } { "classname" "item_shells" "origin" "-352 -592 0" } { "classname" "func_door" "angle" "90" "spawnflags" "1" "targetname" "t13" "wait" "-1" "sounds" "3" "dmg" "100" "model" "*3" } { "health" "1" "angle" "90" "classname" "func_button" "target" "t12" "wait" "-1" "sounds" "1" "model" "*4" } { "classname" "func_button" "angle" "90" "health" "1" "target" "t12" "wait" "-1" "sounds" "1" "model" "*5" } { "classname" "trigger_counter" "targetname" "t12" "count" "2" "target" "t13" "model" "*6" } { "classname" "monster_demon1" "origin" "160 -128 24" "angle" "270" "targetname" "t12" } { "classname" "light" "origin" "-8 -288 64" "light" "200" } { "light" "200" "origin" "328 -288 64" "classname" "light" } { "light" "200" "origin" "-296 -448 -248" "classname" "light" } { "classname" "light" "origin" "160 -368 -248" "light" "200" } { "light" "200" "origin" "616 -448 -248" "classname" "light" } { "classname" "light" "origin" "408 -456 -248" "light" "200" } { "light" "200" "origin" "-40 -424 -248" "classname" "light" } { "classname" "light" "origin" "-280 -448 32" "light" "200" } { "light" "200" "origin" "632 -424 32" "classname" "light" } { "classname" "light" "origin" "160 -480 8" "light" "150" } { "classname" "func_door" "angle" "180" "targetname" "t12" "sounds" "3" "speed" "200" "wait" "-1" "lip" "-2" "model" "*7" } { "classname" "func_door" "angle" "0" "speed" "200" "wait" "-1" "lip" "-2" "model" "*8" } { "classname" "light" "origin" "160 -304 112" "light" "170" } { "classname" "light" "origin" "160 640 104" "light" "200" } { "classname" "func_door" "angle" "-1" "targetname" "t14" "sounds" "1" "model" "*9" } { "classname" "trigger_multiple" "target" "t14" "wait" "10" "model" "*10" } { "targetname" "t28" "classname" "func_door" "angle" "-1" "wait" "-1" "sounds" "1" "speed" "200" "spawnflags" "2048" "model" "*11" } { "angle" "270" "classname" "func_button" "target" "t15" "wait" "-1" "lip" "2" "sounds" "1" "spawnflags" "2048" "model" "*12" } { "classname" "light" "origin" "-296 432 0" "light" "200" } { "light" "200" "origin" "-312 416 152" "classname" "light" } { "classname" "light" "origin" "-184 320 146" "light" "200" } { "classname" "item_key2" "origin" "-552 192 -40" "sounds" "1" "spawnflags" "2048" } { "classname" "item_spikes" "origin" "-680 88 -48" } { "classname" "func_door" "angle" "-2" "spawnflags" "33" "speed" "10" "sounds" "3" "wait" "-1" "targetname" "t16" "dmg" "100" "model" "*13" "lip" "7" // svdijk -- added to prevent z-fighting } { "sounds" "3" "classname" "func_door" "angle" "90" "spawnflags" "2056" "wait" "-1" "model" "*14" } { "spawnflags" "2056" "angle" "270" "classname" "func_door" "wait" "-1" "model" "*15" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t16" "lip" "12" "model" "*16" } { "classname" "light" "origin" "888 1080 -104" "light" "160" } { "light" "160" "origin" "888 888 -104" "classname" "light" } { "classname" "light" "origin" "880 696 -104" "light" "160" } { "light" "160" "origin" "696 888 -104" "classname" "light" } { "classname" "light" "origin" "696 1080 -104" "light" "160" } { "light" "200" "origin" "696 672 -104" "classname" "light" } { "classname" "light" "origin" "568 512 -104" "light" "200" } { "light" "160" "origin" "840 504 -104" "classname" "light" } { "classname" "light" "origin" "832 328 -104" "light" "160" } { "classname" "light" "origin" "936 512 96" "light" "200" } { "classname" "light" "origin" "-248 1080 56" "light" "150" } { "classname" "light" "origin" "888 1264 176" "light" "170" } { "classname" "func_door" "angle" "-2" "targetname" "t17" "sounds" "1" "model" "*17" } { "classname" "trigger_multiple" "target" "t17" "wait" "5" "model" "*18" } { "classname" "light" "origin" "160 120 -24" "light" "160" } { "spawnflags" "256" "classname" "trigger_multiple" "target" "t18" "targetname" "t23" "model" "*19" } { "wait" "0.5" "classname" "trap_spikeshooter" "origin" "88 368 40" "angle" "0" "targetname" "t18" } { "classname" "func_wall" "spawnflags" "2048" "model" "*20" } { "classname" "monster_demon1" "origin" "-160 608 128" "targetname" "t19" } { "classname" "trigger_once" "target" "t19" "model" "*21" } { "classname" "light" "origin" "-528 512 -104" "light" "200" } { "light" "200" "origin" "-344 592 -104" "classname" "light" } { "classname" "light" "origin" "-336 760 -104" "light" "200" } { "light" "200" "origin" "-432 856 -104" "classname" "light" } { "classname" "monster_ogre" "origin" "-416 440 -40" "spawnflags" "1536" "target" "t20" } { "classname" "monster_shambler" "origin" "-272 296 -40" "spawnflags" "256" "target" "t20" } { "classname" "path_corner" "origin" "-328 272 -56" "targetname" "t20" "target" "t21" } { "origin" "-400 480 -56" "classname" "path_corner" "target" "t20" "targetname" "t21" } { "classname" "item_health" "origin" "-600 144 -64" } { "classname" "weapon_supershotgun" "origin" "440 512 0" "spawnflags" "2048" } { "classname" "light" "origin" "-120 176 184" "light" "250" } { "origin" "-96 0 184" "classname" "light" "light" "200" } { "classname" "light" "origin" "312 116 -48" "light" "200" } { "classname" "path_corner" "origin" "8 112 32" "target" "t25" "targetname" "t24" } { "origin" "312 112 32" "classname" "path_corner" "targetname" "t25" "target" "t24" } { "classname" "monster_ogre" "origin" "112 112 48" "target" "t24" "spawnflags" "256" } { "classname" "item_shells" "origin" "88 -160 0" "spawnflags" "1" } { "light" "250" "classname" "light" "origin" "-352 144 56" } { "classname" "monster_demon1" "origin" "-80 -440 -296" "spawnflags" "256" "target" "t26" } { "classname" "path_corner" "origin" "-216 -456 -312" "targetname" "t26" "target" "t27" } { "origin" "536 -448 -312" "classname" "path_corner" "target" "t26" "targetname" "t27" } { "light" "200" "origin" "320 232 -104" "classname" "light" } { "classname" "light" "origin" "312 0 -104" "light" "200" } { "light" "160" "origin" "-8 0 -104" "classname" "light" } { "classname" "light" "origin" "-8 232 -104" "light" "200" } { "light" "200" "origin" "-16 112 -104" "classname" "light" } { "classname" "light" "origin" "-248 -8 -104" "light" "200" } { "light" "200" "origin" "-472 120 -104" "classname" "light" } { "wait" "-1" "classname" "func_door" "angle" "-1" "targetname" "t15" "sounds" "1" "spawnflags" "2048" "model" "*22" } { "classname" "func_door" "angle" "-2" "spawnflags" "2081" "targetname" "t28" "wait" "10" "speed" "200" "sounds" "1" "model" "*23" } { "classname" "trigger_once" "target" "t28" "model" "*24" } { "classname" "trigger_once" "target" "t12" "model" "*25" } { "classname" "monster_ogre" "origin" "160 1432 128" "angle" "270" } { "classname" "monster_ogre" "origin" "-216 784 128" "angle" "90" } { "classname" "info_teleport_destination" "origin" "-360 888 24" "spawnflags" "2048" "targetname" "t1" } { "classname" "monster_zombie" "origin" "-288 -232 -296" "angle" "270" } { "classname" "monster_zombie" "origin" "168 -8 -104" "angle" "90" } { "classname" "monster_ogre" "origin" "648 1232 -64" "angle" "180" } { "sounds" "1" "classname" "func_door" "angle" "-2" "targetname" "t29" "model" "*26" } { "classname" "monster_ogre" "origin" "520 752 24" "angle" "90" "spawnflags" "256" "targetname" "t29" } { "classname" "trigger_once" "target" "t29" "model" "*27" } { "classname" "weapon_nailgun" "origin" "152 1608 136" "spawnflags" "2048" } { "classname" "path_corner" "origin" "544 896 8" "targetname" "t30" "target" "t31" } { "origin" "56 896 72" "classname" "path_corner" "target" "t30" "targetname" "t31" } { "classname" "path_corner" "origin" "168 552 8" "targetname" "t32" "target" "t33" } { "origin" "168 1392 8" "classname" "path_corner" "target" "t32" "targetname" "t33" } { "classname" "monster_knight" "origin" "240 584 24" "target" "t32" } { "classname" "monster_knight" "origin" "504 960 24" "target" "t30" "spawnflags" "256" } { "classname" "monster_knight" "origin" "-16 896 88" "angle" "0" } { "classname" "monster_knight" "origin" "256 1224 24" "angle" "225" "spawnflags" "256" } { "target" "t49" "origin" "-24 1064 16" "classname" "monster_ogre" } { "spawnflags" "256" "angle" "45" "origin" "-184 1080 128" "classname" "monster_ogre" } { "angle" "45" "origin" "-256 1216 128" "classname" "monster_knight" } { "targetname" "t16" "angle" "270" "origin" "784 520 56" "classname" "monster_demon1" } { "classname" "path_corner" "origin" "-352 888 16" "targetname" "t34" "target" "t35" } { "origin" "-120 888 8" "classname" "path_corner" "target" "t34" "targetname" "t35" } { "classname" "monster_ogre" "origin" "-184 912 24" "target" "t34" "spawnflags" "256" } { "classname" "monster_ogre" "origin" "-720 896 64" } { "classname" "monster_knight" "origin" "-344 760 24" "angle" "135" "spawnflags" "256" } { "classname" "monster_knight" "origin" "-392 584 24" "angle" "90" "spawnflags" "256" } { "angle" "90" "classname" "monster_knight" "origin" "-528 528 24" "spawnflags" "768" } { "targetname" "t37" "target" "t36" "origin" "-896 968 48" "classname" "path_corner" } { "target" "t37" "targetname" "t36" "classname" "path_corner" "origin" "-896 568 48" } { "spawnflags" "256" "target" "t36" "origin" "-840 600 24" "classname" "monster_ogre" } { "style" "32" "targetname" "t15" "light" "200" "origin" "-56 304 152" "classname" "light" } { "dmg" "100" "speed" "200" "targetname" "t15" "target" "t38" "classname" "func_train" "model" "*28" } { "target" "t39" "targetname" "t40" "origin" "-216 280 104" "classname" "path_corner" } { "target" "t40" "targetname" "t38" "classname" "path_corner" "origin" "-15 280 104" // svdijk -- changed to prevent z-fighting (was "-16 280 104") } { "target" "t38" "wait" "-1" "targetname" "t39" "origin" "-15 280 104" // svdijk -- changed to prevent z-fighting (was "-16 280 104") "classname" "path_corner" } { "angle" "180" "origin" "680 1472 24" "classname" "monster_ogre" "spawnflags" "256" } { "spawnflags" "256" "angle" "180" "origin" "864 1448 24" "classname" "monster_knight" } { "target" "t42" "targetname" "t41" "origin" "1024 1264 104" "classname" "path_corner" } { "targetname" "t42" "target" "t41" "classname" "path_corner" "origin" "704 1264 104" } { "target" "t41" "origin" "1056 1320 120" "classname" "monster_knight" } { "spawnflags" "257" "origin" "552 1280 128" "classname" "monster_knight" } { "spawnflags" "1" "origin" "432 1280 128" "classname" "monster_knight" } { "spawnflags" "2048" "angle" "0" "wait" "-1" "sounds" "0" "health" "1" "target" "t28" "classname" "func_button" "model" "*29" } { "origin" "-72 296 104" "classname" "item_health" } { "classname" "item_health" "origin" "-64 504 104" } { "origin" "-312 192 -64" "classname" "item_health" } { "spawnflags" "1" "origin" "-80 384 -64" "classname" "item_spikes" } { "origin" "-224 976 104" "classname" "item_shells" } { "target" "t666" "classname" "trigger_multiple" "wait" "10" "model" "*30" } { "target" "t45" "targetname" "t44" "origin" "984 568 8" "classname" "path_corner" } { "target" "t46" "targetname" "t45" "classname" "path_corner" "origin" "976 464 8" } { "target" "t47" "targetname" "t46" "origin" "1224 448 40" "classname" "path_corner" } { "target" "t44" "targetname" "t43" "classname" "path_corner" "origin" "1272 520 40" } { "target" "t48" "targetname" "t47" "classname" "path_corner" "origin" "1224 144 64" } { "targetname" "t48" "target" "t43" "origin" "1344 120 64" "classname" "path_corner" } { "target" "t45" "origin" "968 520 24" "classname" "monster_ogre" } { "spawnflags" "256" "target" "t43" "origin" "1312 328 80" "classname" "monster_knight" } { "spawnflags" "768" "target" "t47" "origin" "1240 296 80" "classname" "monster_ogre" } { "origin" "-360 1064 -8" "classname" "weapon_grenadelauncher" } { "target" "t50" "targetname" "t49" "origin" "-16 1168 0" "classname" "path_corner" } { "targetname" "t50" "target" "t49" "classname" "path_corner" "origin" "-232 1168 0" } { "origin" "1448 -128 -56" "classname" "light" } { "wait" "-1" "classname" "func_door" "angle" "270" "model" "*31" } { "wait" "-1" "targetname" "t52" "sounds" "3" "classname" "func_door" "angle" "90" "model" "*32" } { "classname" "light" "origin" "1984 -184 288" "light" "350" } { "classname" "light" "origin" "1760 -312 -184" "light" "200" } { "origin" "1832 -64 -184" "classname" "light" "light" "200" } { "light" "160" "origin" "1808 -296 -24" "classname" "light" } { "classname" "light" "origin" "1224 -8 -184" "light" "160" } { "light" "160" "origin" "1240 -208 -184" "classname" "light" } { "classname" "light" "origin" "1680 -104 -184" "light" "160" } { "light" "160" "origin" "1584 -304 -184" "classname" "light" } { "origin" "1592 -72 288" "classname" "light" } { "classname" "light" "origin" "1328 -232 288" } { "classname" "light" "origin" "1280 -16 327" "light" "250" } { "classname" "light" "origin" "1792 -152 88" "light" "160" } { "light" "160" "origin" "1632 -296 88" "classname" "light" } { "origin" "1696 -280 288" "classname" "light" } { "classname" "light" "origin" "1240 -224 -8" "light" "200" } { "classname" "func_wall" "spawnflags" "3072" "model" "*33" } { "classname" "func_wall" "spawnflags" "3072" "model" "*34" } { "classname" "func_wall" "spawnflags" "3072" "model" "*35" } { "classname" "func_wall" "spawnflags" "3072" "model" "*36" } { "classname" "func_wall" "spawnflags" "3072" "model" "*37" } { "classname" "monster_ogre" "origin" "1992 -192 200" "angle" "180" "spawnflags" "256" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "targetname" "t51" "model" "*38" } { "classname" "trigger_multiple" "target" "t51" "model" "*39" } { "classname" "func_plat" "model" "*40" } { "classname" "light" "origin" "1480 56 -168" "light" "160" } { "origin" "1432 280 -64" "classname" "light" "light" "160" } { "light" "160" "classname" "light" "origin" "1424 280 96" } { "light" "160" "origin" "1472 232 -168" "classname" "light" } { "classname" "monster_zombie" "origin" "1592 -24 160" "angle" "180" } { "classname" "monster_zombie" "origin" "1432 -304 112" "angle" "135" "spawnflags" "256" } { "classname" "monster_zombie" "origin" "1304 -288 112" "angle" "90" "spawnflags" "256" } { "classname" "monster_zombie" "origin" "1576 -216 136" "angle" "180" "spawnflags" "768" } { "classname" "monster_zombie" "origin" "1928 -80 200" "spawnflags" "768" "angle" "180" } { "angle" "180" "spawnflags" "768" "origin" "1928 -280 200" "classname" "monster_zombie" } { "classname" "trigger_changelevel" "map" "e2m3" "model" "*41" } { "classname" "light" "origin" "80 1544 40" "light" "160" } { "light" "160" "origin" "-112 1544 40" "classname" "light" } { "classname" "item_shells" "origin" "1056 552 8" } { "classname" "light" "origin" "-112 1672 40" "light" "160" } { "light" "160" "origin" "88 1680 40" "classname" "light" } { "classname" "item_health" "origin" "-168 1688 -8" "spawnflags" "1" } { "classname" "monster_knight" "origin" "-112 1616 16" "angle" "45" "spawnflags" "768" } { "classname" "monster_demon1" "origin" "1760 -208 -216" "angle" "180" } { "classname" "trigger_secret" "model" "*42" } { "classname" "trigger_secret" "model" "*43" } { "classname" "trigger_secret" "model" "*44" } { "classname" "trigger_multiple" "target" "t29" "model" "*45" } { "classname" "item_shells" "origin" "-144 -1728 288" "spawnflags" "768" } { "classname" "item_rockets" "origin" "2000 -304 176" "spawnflags" "1793" } { "classname" "item_rockets" "origin" "2000 -112 176" "spawnflags" "1793" } { "origin" "-62 -702 72" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "386 -702 72" } { "origin" "-246 -470 -264" "classname" "ambient_swamp2" } { "classname" "ambient_swamp1" "origin" "554 -454 -264" } { "origin" "162 -430 -264" "classname" "ambient_swamp1" } { "spawnflags" "1" "origin" "-72 576 104" "classname" "item_shells" } { "spawnflags" "2048" "wait" "10" "target" "t16" "classname" "trigger_multiple" "model" "*46" } { "targetname" "t16" "sounds" "4" "wait" "-1" "angle" "-1" "classname" "func_door" "model" "*47" } { "origin" "-184 1480 168" "classname" "light" "light" "160" } { "classname" "light" "origin" "-224 1592 168" "light" "100" } { "target" "t52" "classname" "trigger_once" "model" "*48" } { "mangle" "20 30 0" "origin" "1224 -288 336" "classname" "info_intermission" } { "mangle" "20 180 0" "origin" "-352 760 240" "classname" "info_intermission" } { "mangle" "20 135 0" "origin" "480 -440 208" "classname" "info_intermission" } { "angle" "90" "origin" "-176 -1904 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-128 -1848 264" "angle" "90" } { "angle" "90" "origin" "-192 -1808 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-320 -1824 264" "angle" "90" } { "spawnflags" "1792" "classname" "func_wall" "model" "*49" } { "spawnflags" "1792" "origin" "200 -664 0" "classname" "weapon_lightning" } { "origin" "-184 1512 144" "classname" "item_artifact_super_damage" } { "classname" "item_cells" "origin" "240 -664 0" "spawnflags" "1793" } { "classname" "item_cells" "origin" "392 640 0" "spawnflags" "1793" } { "classname" "item_cells" "origin" "-168 456 104" "spawnflags" "1793" } { "classname" "func_door" "angle" "-1" "spawnflags" "1" "wait" "6" "speed" "1000" "sounds" "3" "targetname" "t15" "model" "*50" } { "classname" "weapon_grenadelauncher" "origin" "1312 280 56" "spawnflags" "3584" } { "sounds" "2" "wait" "5" "message" "Shoot the buttons..." "spawnflags" "3584" "classname" "trigger_multiple" "targetname" "t53" "model" "*51" } { "classname" "trigger_relay" "origin" "-72 -320 48" "targetname" "t13" "killtarget" "t53" } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e2m7.ent���������������������������������������������������������0000644�0000000�0000000�00000142601�12403131422�017040� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "wad" "gfx/tim.wad" "classname" "worldspawn" "sounds" "7" "worldtype" "0" "message" "the Underearth" } { "angle" "90" "origin" "1136 -1100 -72" "classname" "info_player_start" } { "origin" "1184 -776 -152" "classname" "light" "light" "150" } { "classname" "light" "origin" "1704 -584 -184" "light" "150" } { "classname" "light" "origin" "1640 -688 -184" "light" "150" } { "classname" "light" "origin" "1696 -888 -192" "light" "150" } { "classname" "light" "origin" "1088 -960 -152" "light" "150" } { "classname" "light" "origin" "1248 -960 -152" "light" "150" } { "classname" "light" "origin" "1016 -768 -152" "light" "100" } { "classname" "light" "origin" "896 -920 -152" "light" "150" } { "light" "100" "origin" "1584 -208 -112" "classname" "light" } { "light" "100" "origin" "1776 -208 -112" "classname" "light" } { "light" "150" "origin" "1584 -88 -112" "classname" "light" } { "origin" "1774 58 -76" "classname" "light_torch_small_walltorch" } { "light" "100" "origin" "1584 -488 -232" "classname" "light" } { "light" "100" "origin" "1768 -480 -232" "classname" "light" } { "light" "150" "origin" "1752 -112 -176" "classname" "light" } { "light" "150" "origin" "1592 -120 -176" "classname" "light" } { "light" "150" "origin" "1592 -248 -192" "classname" "light" } { "light" "200" "origin" "1768 -240 -192" "classname" "light" } { "light" "150" "origin" "1676 -220 -188" "classname" "light" } { "light" "150" "origin" "1672 -40 -136" "classname" "light" } { "light" "150" "origin" "1676 -376 -252" "classname" "light" } { "light" "250" "origin" "1112 952 -92" "classname" "light" } { "light" "200" "origin" "1280 928 -152" "classname" "light" } { "classname" "light" "origin" "704 952 -92" "light" "250" } { "classname" "light" "origin" "824 1112 -92" "light" "200" } { "classname" "light" "origin" "952 760 -92" "light" "200" } { "classname" "light" "origin" "824 760 -92" "light" "200" } { "light" "250" "origin" "952 1112 -92" "classname" "light" } { "classname" "light" "origin" "1128 -848 288" "light" "500" } { "classname" "light" "origin" "1144 -432 288" } { "classname" "light" "origin" "864 -552 272" "light" "200" } { "classname" "light" "origin" "1392 -568 168" "light" "200" } { "classname" "light" "origin" "1416 -592 -24" "light" "150" } { "classname" "light" "origin" "888 -584 -24" "light" "150" } { "classname" "light_torch_small_walltorch" "origin" "1058 -466 -24" "light" "225" } { "origin" "1214 -466 -24" "classname" "light_torch_small_walltorch" "light" "225" } { "classname" "light_torch_small_walltorch" "origin" "1198 -66 40" "light" "300" } { "classname" "light" "origin" "1144 -204 172" "light" "150" } { "classname" "light" "origin" "1144 -292 -32" "light" "150" } { "classname" "item_spikes" "origin" "880 -592 -96" "spawnflags" "1" } { "classname" "item_health" "origin" "1068 -944 -96" } { "classname" "light" "origin" "1128 -1084 96" "light" "300" } { "classname" "light" "origin" "888 -848 248" "light" "150" } { "light" "150" "origin" "1504 -896 248" "classname" "light" } { "classname" "light" "origin" "1304 -1048 24" "light" "225" } { "classname" "light" "origin" "1520 -872 -192" "light" "150" } { "light" "100" "origin" "1384 -776 -184" "classname" "light" } { "classname" "light" "origin" "1368 -912 -184" "light" "100" } { "classname" "light" "origin" "1584 496 148" "light" "200" } { "light" "200" "origin" "1488 496 148" "classname" "light" } { "classname" "light" "origin" "1688 164 148" "light" "200" } { "light" "200" "origin" "1352 496 148" "classname" "light" } { "classname" "light" "origin" "1608 496 -36" "light" "200" } { "light" "200" "origin" "1456 496 -36" "classname" "light" } { "classname" "light" "origin" "1692 600 -12" "light" "200" } { "light" "200" "origin" "1274 618 -64" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1274 378 -64" "light" "200" } { "classname" "light" "origin" "1256 496 -40" "light" "200" } { "spawnflags" "2056" "wait" "-1" "classname" "func_door" "angle" "270" "model" "*1" } { "wait" "-1" "spawnflags" "2056" "sounds" "3" "angle" "90" "classname" "func_door" "model" "*2" } { "light" "200" "origin" "1968 1792 -257" "classname" "light" } { "light" "250" "origin" "1880 1792 -105" "classname" "light" } { "classname" "light" "origin" "1976 1944 56" "light" "150" } { "light" "150" "origin" "1992 1624 64" "classname" "light" } { "classname" "light" "origin" "1944 1736 64" "light" "150" } { "light" "150" "origin" "1944 1832 64" "classname" "light" } { "classname" "light" "origin" "1128 496 -24" "light" "250" } { "light" "150" "origin" "1120 632 -24" "classname" "light" } { "light" "200" "origin" "928 544 -24" "classname" "light" } { "classname" "light" "origin" "640 664 -8" "light" "200" } { "light" "200" "origin" "848 672 -8" "classname" "light" } { "classname" "light" "origin" "1024 544 -188" "light" "175" } { "light" "250" "origin" "64 192 136" "classname" "light" } { "classname" "light" "origin" "528 184 136" "light" "250" } { "light" "200" "origin" "72 408 8" "classname" "light" } { "classname" "light" "origin" "80 -48 8" "light" "200" } { "light" "250" "origin" "400 384 80" "classname" "light" } { "classname" "light" "origin" "392 -16 80" "light" "250" } { "classname" "light" "origin" "312 184 -80" "light" "200" } { "light" "200" "origin" "440 184 -80" "classname" "light" } { "classname" "light" "origin" "504 368 -120" "light" "250" } { "light" "150" "origin" "632 192 -120" "classname" "light" } { "classname" "light" "origin" "504 -16 -120" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "774 446 -172" "light" "250" } { "origin" "774 -70 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "light" "250" "origin" "896 -128 152" "classname" "light" } { "classname" "light" "origin" "896 184 152" "light" "250" } { "light" "150" "origin" "656 184 216" "classname" "light" } { "classname" "light" "origin" "304 368 -152" "light" "200" } { "light" "200" "origin" "0 480 -168" "classname" "light" } { "classname" "light" "origin" "96 376 -168" "light" "200" } { "classname" "light" "origin" "16 1480 -96" "light" "200" } { "light" "200" "origin" "1280 1824 -120" "classname" "light" } { "light" "200" "origin" "504 1816 -120" "classname" "light" } { "classname" "light" "origin" "712 1808 -120" "light" "200" } { "light" "200" "origin" "1064 1808 -120" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "858 1950 -172" "light" "250" } { "origin" "658 1950 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "666 1682 -172" "light" "250" } { "origin" "858 1682 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "classname" "light" "origin" "1248 1384 -32" "light" "200" } { "classname" "light" "origin" "1688 936 -136" "light" "200" } { "light" "250" "origin" "1856 1444 -52" "classname" "light" } { "light" "150" "origin" "1864 1316 -192" "classname" "light" } { "classname" "light" "origin" "1776 1212 -192" "light" "150" } { "light" "150" "origin" "1696 1076 -192" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "1770 730 -64" "light" "250" } { "classname" "light" "origin" "1760 1720 -201" "light" "250" } { "classname" "light" "origin" "1632 1520 -201" "light" "200" } { "classname" "light" "origin" "1984 1504 -201" "light" "200" } { "light" "250" "classname" "light_torch_small_walltorch" "origin" "1874 2104 -300" } { "light" "250" "origin" "1712 2104 -300" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light" "origin" "1792 2048 48" } { "classname" "light_flame_large_yellow" "origin" "1362 1778 0" } { "classname" "light" "origin" "1408 1776 -124" "light" "200" } { "classname" "light" "origin" "1520 1880 -84" "light" "175" } { "light" "175" "origin" "1416 1512 -84" "classname" "light" } { "classname" "light" "origin" "1376 1568 -164" "light" "150" } { "light" "150" "origin" "1416 1888 -164" "classname" "light" } { "classname" "light" "origin" "1544 2072 -164" "light" "150" } { "classname" "light" "origin" "1552 1968 36" "light" "250" } { "classname" "light" "origin" "1416 1968 -16" "light" "175" } { "light" "175" "origin" "1416 2176 -16" "classname" "light" } { "classname" "light" "origin" "1240 2176 -16" "light" "175" } { "light" "175" "origin" "1240 2000 -16" "classname" "light" } { "classname" "light" "origin" "1264 1576 -72" "light" "200" } { "light" "200" "origin" "992 1480 -40" "classname" "light" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "968 1632 -132" } { "light" "200" "origin" "968 1328 -132" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1474 2234 -133" "light" "200" } { "origin" "1182 2234 -133" "classname" "light_torch_small_walltorch" "light" "200" } { "classname" "light" "origin" "1936 1480 48" "light" "150" } { "light" "150" "origin" "1544 1528 64" "classname" "light" } { "classname" "light" "origin" "1472 1488 24" "light" "150" } { "classname" "light" "origin" "1400 1664 96" "light" "150" } { "light" "200" "origin" "1792 2176 -221" "classname" "light" } { "classname" "light" "origin" "1880 2288 -221" "light" "200" } { "light" "200" "origin" "2048 2288 -221" "classname" "light" } { "classname" "light" "origin" "2128 2208 -221" "light" "200" } { "light" "200" "origin" "2160 1992 -205" "classname" "light" } { "origin" "2288 1952 -29" "classname" "light" } { "light" "250" "origin" "2274 1738 -172" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "2274 1682 -172" "light" "250" } { "light" "200" "origin" "2376 2184 -152" "classname" "light" } { "light" "200" "origin" "2618 1658 -169" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "2618 1368 -169" "light" "200" } { "light" "200" "origin" "2176 1488 -169" "classname" "light_torch_small_walltorch" } { "light" "200" "origin" "2298 626 24" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1930 738 24" "light" "200" } { "light" "200" "origin" "2050 394 24" "classname" "light_torch_small_walltorch" } { "classname" "func_plat" "model" "*3" } { "light" "150" "origin" "2152 1784 -312" "classname" "light" } { "classname" "light" "origin" "2232 936 -4" "light" "200" } { "classname" "light" "origin" "2232 1040 48" } { "classname" "light_torch_small_walltorch" "origin" "2034 1034 -164" "light" "200" } { "classname" "light" "origin" "2304 1040 280" "light" "200" } { "light" "200" "origin" "2168 1040 280" "classname" "light" } { "origin" "2130 2452 -112" "classname" "light_flame_large_yellow" "light" "250" } { "classname" "light_flame_large_yellow" "origin" "1858 2452 -112" "light" "250" } { "classname" "light" "origin" "2132 2416 -188" "light" "150" } { "light" "150" "origin" "1860 2416 -188" "classname" "light" } { "light" "200" "origin" "2256 1968 -453" "classname" "light" } { "classname" "light" "origin" "2256 2184 -453" "light" "200" } { "light" "200" "origin" "2216 2384 -453" "classname" "light" } { "classname" "light" "origin" "1792 2400 -453" "light" "200" } { "light" "175" "origin" "1984 2400 -453" "classname" "light" } { "light" "150" "origin" "2168 1608 -9" "classname" "light" } { "classname" "light" "origin" "2368 1600 -9" "light" "150" } { "light" "150" "origin" "2240 1424 44" "classname" "light" } { "classname" "light" "origin" "2400 1424 44" "light" "150" } { "light" "150" "origin" "2560 1424 44" "classname" "light" } { "classname" "light" "origin" "2560 1560 44" "light" "175" } { "light" "150" "origin" "2232 1288 44" "classname" "light" } { "light" "175" "origin" "2384 1424 -160" "classname" "light" } { "classname" "light" "origin" "2232 1288 -160" "light" "175" } { "light" "150" "origin" "2164 932 -172" "classname" "light" } { "classname" "light" "origin" "2308 932 -172" "light" "150" } { "light" "150" "origin" "2232 776 24" "classname" "light" } { "classname" "light" "origin" "2192 664 24" "light" "150" } { "light" "150" "origin" "2016 696 24" "classname" "light" } { "classname" "light" "origin" "1912 496 24" "light" "150" } { "light" "175" "origin" "80 1616 -120" "classname" "light" } { "classname" "light" "origin" "72 1888 -120" "light" "175" } { "light" "175" "origin" "296 1616 -120" "classname" "light" } { "light" "175" "origin" "304 1888 -120" "classname" "light" } { "targetname" "t20" "angle" "90" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t21" "angle" "120" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t22" "angle" "150" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t19" "angle" "60" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t18" "angle" "30" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t17" "angle" "0" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t24" "angle" "210" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t23" "angle" "180" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t25" "angle" "240" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t26" "angle" "270" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t27" "angle" "300" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t28" "angle" "330" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "delay" ".1" "targetname" "t29" "target" "t17" "classname" "trigger_multiple" "model" "*4" } { "delay" ".1" "targetname" "t17" "target" "t18" "classname" "trigger_multiple" "model" "*5" } { "delay" ".1" "targetname" "t18" "target" "t19" "classname" "trigger_multiple" "model" "*6" } { "delay" ".1" "targetname" "t19" "target" "t20" "classname" "trigger_multiple" "model" "*7" } { "delay" ".1" "targetname" "t20" "target" "t21" "classname" "trigger_multiple" "model" "*8" } { "delay" ".1" "targetname" "t21" "target" "t22" "classname" "trigger_multiple" "model" "*9" } { "delay" ".1" "targetname" "t22" "target" "t23" "classname" "trigger_multiple" "model" "*10" } { "delay" ".1" "targetname" "t23" "target" "t24" "classname" "trigger_multiple" "model" "*11" } { "delay" ".1" "targetname" "t24" "target" "t25" "classname" "trigger_multiple" "model" "*12" } { "delay" ".1" "targetname" "t25" "target" "t26" "classname" "trigger_multiple" "model" "*13" } { "delay" ".1" "targetname" "t26" "target" "t27" "classname" "trigger_multiple" "model" "*14" } { "delay" ".1" "targetname" "t27" "target" "t28" "classname" "trigger_multiple" "model" "*15" } { "target" "t29" "wait" "1.3" "classname" "trigger_multiple" "model" "*16" } { "origin" "192 1750 -188" "classname" "light_flame_large_yellow" } { "light" "125" "origin" "214 1752 -166" "classname" "light" } { "classname" "light" "origin" "192 1774 -166" "light" "125" } { "light" "125" "origin" "170 1750 -166" "classname" "light" } { "classname" "light" "origin" "194 1726 -166" "light" "125" } { "target" "t31" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*17" } { "target" "t31" "angle" "180" "wait" "-1" "classname" "func_button" "model" "*18" } { "target" "t31" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*19" } { "target" "t31" "angle" "90" "wait" "-1" "classname" "func_button" "model" "*20" } { "wait" "-1" "targetname" "t30" "sounds" "4" "speed" "50" "angle" "-1" "classname" "func_door" "model" "*21" } { "count" "4" "targetname" "t31" "target" "t30" "classname" "trigger_counter" "model" "*22" } { "light" "150" "origin" "2424 1080 -176" "classname" "light" } { "classname" "light" "origin" "2424 992 -176" "light" "150" } { "targetname" "t40" "angle" "180" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "160" } { "targetname" "t40" "angle" "140" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "120" } { "targetname" "t40" "angle" "200" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "220" } { "targetname" "t40" "angle" "240" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t41" "target" "t40" "wait" ".5" "classname" "trigger_multiple" "model" "*23" } { "target" "t41" "classname" "trigger_multiple" "model" "*24" } { "target" "t41" "classname" "trigger_multiple" "model" "*25" } { "target" "t41" "classname" "trigger_multiple" "model" "*26" } { "target" "t41" "classname" "trigger_multiple" "model" "*27" } { "target" "t41" "classname" "trigger_multiple" "model" "*28" } { "target" "t41" "classname" "trigger_multiple" "model" "*29" } { "target" "t41" "classname" "trigger_multiple" "model" "*30" } { "light" "125" "origin" "2196 1200 -204" "classname" "light" } { "classname" "light" "origin" "2284 1200 -204" "light" "125" } { "light" "125" "origin" "2284 1112 -204" "classname" "light" } { "classname" "light" "origin" "2388 1104 -204" "light" "125" } { "light" "125" "origin" "2284 1000 -204" "classname" "light" } { "classname" "light" "origin" "2140 1008 -204" "light" "125" } { "light" "125" "origin" "2132 1096 -204" "classname" "light" } { "classname" "light" "origin" "2132 1160 -204" "light" "125" } { "light" "200" "origin" "528 1816 -392" "classname" "light" } { "classname" "light" "origin" "736 1808 -392" "light" "200" } { "light" "200" "origin" "1040 1808 -392" "classname" "light" } { "classname" "light" "origin" "744 1424 -392" "light" "200" } { "light" "200" "origin" "752 1288 -416" "classname" "light" } { "light" "200" "origin" "760 1064 -376" "classname" "light" } { "classname" "func_train" "spawnflags" "33" "targetname" "t42" "dmg" "1000" "sounds" "1" "target" "t124" "speed" "250" "model" "*31" } { "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t43" "speed" "50" "sounds" "3" "model" "*32" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t42" "sounds" "1" "model" "*33" } { "classname" "trigger_once" "target" "t43" "targetname" "t42" "delay" "2" "model" "*34" } { "classname" "light" "origin" "1936 1784 -288" "light" "125" } { "classname" "monster_ogre" "origin" "1976 1784 -328" "angle" "180" } { "classname" "func_door" "angle" "90" "wait" "-1" "sounds" "1" "model" "*35" } { "classname" "func_door" "angle" "270" "targetname" "t44" "wait" "-1" "model" "*36" } { "classname" "light" "origin" "64 264 8" "light" "125" } { "light" "125" "origin" "64 120 8" "classname" "light" } { "classname" "light" "origin" "64 192 8" "light" "100" } { "classname" "trigger_once" "target" "t44" "model" "*37" } { "classname" "light" "origin" "512 184 -8" "light" "175" } { "targetname" "t119" "classname" "func_door" "angle" "90" "wait" "-1" "speed" "40" "model" "*38" } { "targetname" "t119" "classname" "func_door" "wait" "-1" "angle" "270" "speed" "40" "sounds" "4" "model" "*39" } { "targetname" "t119" "classname" "func_door" "wait" "-1" "angle" "-1" "speed" "30" "message" "Go for a swim first..." "sounds" "3" "model" "*40" "origin" "-1 0 0" // svdijk -- added to prevent z-fighting } { "classname" "func_button" "angle" "0" "wait" "-1" "target" "t45" "model" "*41" } { "classname" "light" "origin" "36 184 84" "light" "75" } { "classname" "light" "origin" "752 184 -192" "light" "150" } { "classname" "light" "origin" "544 536 -152" "light" "125" } { "classname" "func_door" "angle" "-2" "sounds" "1" "wait" "-1" "targetname" "t45" "model" "*42" } { "wait" "-1" "sounds" "1" "angle" "-2" "classname" "func_door" "targetname" "t45" "model" "*43" } { "light" "125" "origin" "544 -152 -152" "classname" "light" } { "classname" "item_artifact_envirosuit" "origin" "1024 492 -232" } { "classname" "item_armor1" "origin" "2128 1752 -352" } { "classname" "light_flame_small_yellow" "origin" "1024 368 -4" "light" "250" } { "classname" "light" "origin" "1024 400 -64" "light" "150" } { "wait" "5" "sounds" "1" "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t51" "model" "*44" } { "wait" "5" "sounds" "1" "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t51" "model" "*45" } { "sounds" "3" "classname" "func_button" "angle" "270" "wait" "3" "target" "t51" "model" "*46" } { "classname" "light" "origin" "1224 712 -216" "light" "100" } { "classname" "light" "origin" "1232 768 -192" "light" "100" } { "light" "75" "origin" "1168 760 -232" "classname" "light" } { "light" "100" "origin" "1232 800 -208" "classname" "light" } { "sounds" "1" "origin" "1860 472 -8" "classname" "item_key2" "spawnflags" "2048" } { "classname" "light" "origin" "1112 1568 -40" "light" "200" } { "light" "150" "origin" "-96 1440 -160" "classname" "light" } { "classname" "light" "origin" "384 1440 -160" "light" "150" } { "light" "200" "origin" "248 1408 -96" "classname" "light" } { "light" "150" "origin" "968 1480 -128" "classname" "light" } { "light" "150" "origin" "1008 -592 -32" "classname" "light" } { "classname" "light" "origin" "1264 -592 -32" "light" "150" } { "light" "200" "origin" "880 -840 -56" "classname" "light" } { "classname" "light" "origin" "1376 -856 -56" "light" "200" } { "light" "175" "origin" "264 184 -8" "classname" "light" } { "light" "175" "origin" "1464 -864 -208" "classname" "light" } { "light" "175" "origin" "1816 160 -56" "classname" "light" } { "classname" "light" "origin" "1560 160 -56" "light" "175" } { "light" "175" "origin" "1544 1632 104" "classname" "light" } { "classname" "light" "origin" "1792 1624 128" "light" "175" } { "classname" "item_health" "origin" "1068 -980 -104" } { "spawnflags" "1" "classname" "item_shells" "origin" "1344 -1160 -96" } { "classname" "monster_ogre" "origin" "1008 -128 40" "angle" "315" "targetname" "t59" "spawnflags" "1" } { "classname" "trigger_once" "target" "t59" "model" "*47" } { "classname" "monster_ogre" "origin" "896 96 56" "angle" "270" "target" "t60" "spawnflags" "1" } { "classname" "path_corner" "origin" "896 208 40" "target" "t60" "targetname" "t61" } { "origin" "896 -16 40" "classname" "path_corner" "targetname" "t60" "target" "t61" } { "classname" "path_corner" "origin" "168 392 -56" "target" "t62" "targetname" "t63" } { "origin" "168 -16 -56" "classname" "path_corner" "targetname" "t62" "target" "t63" } { "classname" "path_corner" "origin" "88 344 -56" "targetname" "t64" "target" "t65" "spawnflags" "256" } { "origin" "88 72 -56" "classname" "path_corner" "target" "t64" "targetname" "t65" "spawnflags" "256" } { "classname" "monster_hell_knight" "origin" "88 224 -40" "angle" "90" "target" "t64" "spawnflags" "257" } { "classname" "monster_hell_knight" "origin" "168 232 -40" "angle" "270" "target" "t62" "spawnflags" "1" } { "classname" "monster_zombie" "origin" "544 -120 -208" "angle" "90" "targetname" "t45" } { "classname" "monster_zombie" "origin" "544 496 -208" "angle" "270" "targetname" "t45" } { "classname" "monster_wizard" "origin" "664 428 216" "angle" "225" "spawnflags" "1" } { "angle" "135" "origin" "664 -56 216" "classname" "monster_wizard" "spawnflags" "257" } { "classname" "light" "origin" "1736 88 -40" "light" "100" } { "classname" "monster_ogre" "origin" "904 -120 56" "angle" "0" "targetname" "t66" "spawnflags" "1281" } { "classname" "trigger_once" "target" "t66" "spawnflags" "256" "model" "*48" } { "classname" "item_health" "origin" "1168 -408 -80" "spawnflags" "1" } { "classname" "item_health" "origin" "1168 -104 -16" } { "classname" "item_spikes" "origin" "928 216 32" } { "classname" "item_rockets" "origin" "632 -48 32" } { "classname" "item_health" "origin" "32 392 -64" } { "light" "200" "origin" "1688 288 148" "classname" "light" } { "classname" "light" "origin" "1688 464 148" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "1814 622 -64" "light" "250" } { "classname" "light" "origin" "1768 344 -72" "light" "200" } { "classname" "trigger_monsterjump" "angle" "0" "model" "*49" } { "targetname" "t100" "classname" "monster_ogre" "origin" "1504 272 24" "angle" "0" "spawnflags" "256" } { "targetname" "t68" "target" "t67" "origin" "1352 576 -120" "classname" "path_corner" "spawnflags" "256" } { "target" "t68" "targetname" "t67" "classname" "path_corner" "origin" "1352 416 -120" "spawnflags" "256" } { "target" "t68" "angle" "90" "origin" "1360 480 -104" "classname" "monster_demon1" "spawnflags" "257" } { "targetname" "t70" "target" "t69" "origin" "1472 496 -120" "classname" "path_corner" } { "target" "t70" "targetname" "t69" "classname" "path_corner" "origin" "1688 496 -120" } { "target" "t69" "angle" "270" "origin" "1648 544 -104" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t71" "targetname" "t72" "origin" "1984 688 -24" "classname" "path_corner" "spawnflags" "256" } { "target" "t72" "targetname" "t71" "classname" "path_corner" "origin" "1984 448 -24" "spawnflags" "256" } { "target" "t71" "angle" "270" "origin" "1992 536 -8" "classname" "monster_ogre" "spawnflags" "257" } { "target" "t74" "targetname" "t73" "origin" "2120 680 -24" "classname" "path_corner" } { "targetname" "t74" "target" "t73" "classname" "path_corner" "origin" "2240 680 -24" } { "target" "t74" "angle" "225" "origin" "2256 736 -8" "classname" "monster_ogre" "spawnflags" "1" } { "targetname" "t78" "angle" "90" "origin" "2232 1312 -8" "classname" "monster_ogre" "spawnflags" "256" } { "target" "t76" "angle" "90" "origin" "2232 1008 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "targetname" "t76" "target" "t75" "origin" "2120 968 -216" "classname" "path_corner" } { "target" "t76" "targetname" "t75" "classname" "path_corner" "origin" "2336 968 -216" } { "classname" "light" "origin" "2384 2400 -152" "light" "200" } { "targetname" "t77" "wait" "-1" "sounds" "1" "speed" "300" "angle" "-2" "classname" "func_door" "model" "*50" } { "targetname" "t77" "angle" "180" "origin" "2512 2312 -200" "classname" "monster_demon1" "spawnflags" "256" } { "targetname" "t77" "classname" "monster_demon1" "origin" "2512 2160 -200" "angle" "180" } { "classname" "item_health" "origin" "2504 2200 -224" } { "light" "150" "origin" "2536 2312 -128" "classname" "light" } { "classname" "light" "origin" "2536 2160 -128" "light" "150" } { "target" "t77" "classname" "trigger_once" "model" "*51" } { "spawnflags" "2" "origin" "2368 2336 -224" "classname" "item_health" } { "spawnflags" "1" "origin" "2504 2240 -224" "classname" "item_spikes" } { "origin" "2408 2072 -224" "classname" "item_shells" } { "target" "t78" "classname" "trigger_once" "model" "*52" } { "targetname" "t78" "angle" "90" "origin" "2240 1272 -200" "classname" "monster_demon1" } { "light" "150" "origin" "1120 1384 -40" "classname" "light" } { "light" "200" "origin" "1200 1248 -104" "classname" "light" } { "light" "250" "origin" "1288 1032 -4" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "1256 1032 -64" "classname" "light" } { "classname" "light_flame_small_yellow" "origin" "568 1032 -4" "light" "250" } { "classname" "light" "origin" "600 1032 -64" "light" "150" } { "light" "250" "origin" "888 1272 -4" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "888 1240 -64" "classname" "light" } { "light" "200" "origin" "608 1232 -108" "classname" "light" } { "target" "t79" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*53" } { "targetname" "t79" "message" "This door is opened near by..." "sounds" "3" "speed" "35" "angle" "-1" "wait" "-1" "classname" "func_door" "model" "*54" } { "light" "100" "origin" "580 1208 -148" "classname" "light" } { "light" "200" "origin" "1224 736 -8" "classname" "light" } { "target" "t80" "classname" "trigger_once" "model" "*55" } { "targetname" "t80" "angle" "315" "origin" "640 1088 128" "classname" "monster_wizard" } { "targetname" "t80" "classname" "monster_wizard" "origin" "616 720 128" "angle" "0" } { "targetname" "t80" "angle" "180" "origin" "1280 680 128" "classname" "monster_wizard" "spawnflags" "256" } { "target" "t82" "origin" "1248 1080 24" "classname" "monster_wizard" "spawnflags" "1" } { "targetname" "t82" "target" "t81" "origin" "1168 1064 8" "classname" "path_corner" } { "target" "t82" "targetname" "t81" "classname" "path_corner" "origin" "720 1064 8" } { "targetname" "t80" "classname" "monster_wizard" "origin" "584 1112 128" "angle" "315" "spawnflags" "256" } { "origin" "1256 944 -184" "classname" "item_health" } { "spawnflags" "1" "origin" "1116 584 -256" "classname" "item_spikes" } { "targetname" "t79" "angle" "315" "origin" "1000 1464 -168" "classname" "monster_ogre" } { "target" "t85" "targetname" "t86" "origin" "1456 1824 -192" "classname" "path_corner" "spawnflags" "256" } { "target" "t86" "targetname" "t85" "classname" "path_corner" "origin" "1456 1560 -192" "spawnflags" "256" } { "target" "t85" "angle" "270" "origin" "1456 1664 -176" "classname" "monster_ogre" "spawnflags" "256" } { "targetname" "t91" "angle" "270" "origin" "1560 1944 -320" "classname" "monster_zombie" "spawnflags" "256" } { "targetname" "t91" "classname" "monster_zombie" "origin" "1600 1912 -320" "angle" "270" } { "angle" "225" "origin" "1960 1984 -320" "classname" "monster_zombie" } { "targetname" "t91" "classname" "monster_zombie" "origin" "1904 1928 -320" "angle" "225" } { "targetname" "t91" "angle" "270" "origin" "1624 1768 -320" "classname" "monster_zombie" } { "target" "t87" "classname" "monster_zombie" "origin" "1696 1912 -320" "angle" "0" } { "target" "t89" "angle" "270" "origin" "1704 1800 -320" "classname" "monster_zombie" } { "target" "t87" "targetname" "t88" "origin" "1648 1912 -336" "classname" "path_corner" } { "target" "t88" "targetname" "t87" "classname" "path_corner" "origin" "1848 1904 -336" } { "targetname" "t90" "target" "t89" "origin" "1648 1824 -336" "classname" "path_corner" } { "target" "t90" "targetname" "t89" "classname" "path_corner" "origin" "1768 1752 -336" } { "target" "t91" "classname" "trigger_once" "model" "*56" } { "spawnflags" "1" "origin" "1496 1808 -200" "classname" "item_health" } { "spawnflags" "1" "origin" "1184 2176 -192" "classname" "item_health" } { "classname" "item_health" "origin" "1184 2128 -192" "spawnflags" "1" } { "spawnflags" "1" "origin" "1264 1680 -192" "classname" "item_health" } { "target" "t92" "targetname" "t93" "origin" "2376 2304 -216" "classname" "path_corner" } { "target" "t93" "targetname" "t92" "classname" "path_corner" "origin" "2376 1984 -216" } { "target" "t95" "targetname" "t94" "origin" "2144 1608 -216" "classname" "path_corner" } { "target" "t94" "targetname" "t95" "classname" "path_corner" "origin" "2376 1608 -216" } { "target" "t92" "angle" "270" "origin" "2376 2176 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "135" "origin" "2416 1760 -200" "classname" "monster_hell_knight" "spawnflags" "257" } { "target" "t94" "angle" "180" "origin" "2320 1608 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "90" "origin" "2152 1840 -200" "classname" "monster_ogre" "spawnflags" "257" } { "target" "t97" "targetname" "t96" "origin" "2096 2376 -216" "classname" "path_corner" "spawnflags" "256" } { "target" "t96" "targetname" "t97" "classname" "path_corner" "origin" "2232 2208 -216" "spawnflags" "256" } { "target" "t96" "angle" "135" "origin" "2200 2264 -200" "classname" "monster_wizard" "spawnflags" "257" } { "origin" "2104 1544 -224" "classname" "item_shells" } { "origin" "2176 1240 -32" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "2256 1240 -32" } { "origin" "1928 584 -32" "classname" "item_shells" } { "spawnflags" "1" "origin" "2040 1072 -32" "classname" "item_health" } { "classname" "item_health" "origin" "2040 1024 -32" "spawnflags" "1" } { "angle" "225" "origin" "2352 1160 -200" "classname" "monster_hell_knight" "spawnflags" "256" } { "angle" "180" "origin" "1864 1192 -216" "classname" "monster_zombie" } { "classname" "monster_zombie" "origin" "1776 1192 -216" "angle" "180" } { "target" "t99" "targetname" "t98" "origin" "1688 1192 -232" "classname" "path_corner" } { "target" "t98" "targetname" "t99" "classname" "path_corner" "origin" "1688 1048 -232" } { "target" "t98" "angle" "90" "origin" "1688 1112 -216" "classname" "monster_zombie" } { "origin" "536 416 32" "classname" "item_shells" } { "target" "t100" "classname" "trigger_once" "spawnflags" "256" "model" "*57" } { "origin" "1784 408 -128" "classname" "item_health" } { "classname" "item_health" "origin" "1784 448 -128" } { "origin" "1736 728 -128" "classname" "item_rockets" } { "target" "t101" "sounds" "1" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*58" } { "light" "250" "origin" "1418 234 52" "classname" "light_torch_small_walltorch" } { "targetname" "t101" "classname" "trigger_secret" "model" "*59" } { "targetname" "t102" "angle" "180" "classname" "trigger_monsterjump" "model" "*60" } { "target" "t102" "killtarget" "t102" "classname" "trigger_once" "model" "*61" } { "origin" "1568 1968 -352" "classname" "item_health" } { "classname" "item_health" "origin" "1608 1968 -352" } { "origin" "2112 1776 -352" "classname" "item_shells" "spawnflags" "2048" } { "origin" "1920 2232 -352" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "2008 2232 -352" } { "classname" "item_shells" "origin" "2176 1440 -224" } { "target" "t66" "classname" "trigger_once" "model" "*62" } { "origin" "1744 0 -128" "classname" "item_spikes" "spawnflags" "1" } { "target" "t103" "targetname" "t104" "origin" "-56 1432 -224" "classname" "path_corner" "spawnflags" "256" } { "target" "t104" "targetname" "t103" "classname" "path_corner" "origin" "312 1432 -224" "spawnflags" "256" } { "target" "t103" "origin" "40 1440 -208" "classname" "monster_ogre" "spawnflags" "257" } { "angle" "45" "origin" "56 1616 -208" "classname" "monster_hell_knight" "spawnflags" "1" } { "target" "t105" "targetname" "t106" "origin" "520 1816 -232" "classname" "path_corner" } { "target" "t106" "targetname" "t105" "classname" "path_corner" "origin" "920 1816 -232" } { "target" "t105" "origin" "624 1800 -216" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "0" "origin" "480 1824 64" "classname" "monster_wizard" "spawnflags" "257" } { "targetname" "t107" "classname" "monster_wizard" "origin" "656 1816 64" "angle" "0" "spawnflags" "1" } { "targetname" "t107" "angle" "0" "origin" "840 1816 64" "classname" "monster_wizard" "spawnflags" "257" } { "target" "t107" "classname" "trigger_once" "model" "*63" } { "origin" "1440 2200 -192" "classname" "item_shells" } { "classname" "item_shells" "origin" "1440 2160 -192" } { "spawnflags" "1" "origin" "1184 1976 -192" "classname" "item_spikes" } { "target" "t109" "targetname" "t108" "origin" "1240 2000 -184" "classname" "path_corner" } { "target" "t108" "targetname" "t109" "classname" "path_corner" "origin" "1240 1760 -184" } { "target" "t108" "angle" "90" "origin" "1240 1904 -168" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t110" "classname" "trigger_once" "spawnflags" "256" "model" "*64" } { "targetname" "t110" "angle" "45" "origin" "1216 2088 -168" "classname" "monster_ogre" "spawnflags" "1281" } { "classname" "item_health" "origin" "1496 1768 -200" } { "target" "t111" "classname" "trigger_once" "model" "*65" } { "targetname" "t111" "angle" "315" "origin" "764 -60 -208" "classname" "monster_zombie" } { "targetname" "t111" "angle" "45" "origin" "764 436 -208" "classname" "monster_zombie" } { "targetname" "t111" "angle" "225" "origin" "284 -56 -208" "classname" "monster_zombie" "spawnflags" "256" } { "targetname" "t119" "wait" "-1" "speed" "40" "angle" "90" "classname" "func_door" "model" "*66" } { "origin" "1280 592 -128" "classname" "item_shells" } { "classname" "item_shells" "origin" "576 416 32" } { "classname" "item_spikes" "origin" "904 504 -128" "spawnflags" "1" } { "origin" "904 464 -128" "classname" "item_spikes" "spawnflags" "1" } { "classname" "item_health" "origin" "1024 912 -152" "spawnflags" "1" } { "classname" "item_spikes" "origin" "720 848 -184" "spawnflags" "1" } { "classname" "path_corner" "origin" "1224 1192 -176" "targetname" "t112" "target" "t113" } { "origin" "1216 896 -176" "classname" "path_corner" "targetname" "t113" "target" "t112" } { "classname" "monster_ogre" "origin" "1224 992 -160" "angle" "90" "target" "t112" } { "classname" "item_shells" "origin" "968 1600 -184" } { "classname" "item_artifact_super_damage" "origin" "1444 308 -104" } { "classname" "light" "origin" "992 -128 72" "light" "100" } { "classname" "item_shells" "origin" "1672 1008 -240" } { "classname" "item_health" "origin" "2264 1320 -224" } { "classname" "monster_wizard" "origin" "2120 1664 -72" "angle" "315" "spawnflags" "1" } { "classname" "item_health" "origin" "2016 392 -32" } { "classname" "monster_hell_knight" "origin" "360 1744 -208" "angle" "90" "targetname" "t114" "spawnflags" "257" } { "classname" "trigger_once" "target" "t114" "spawnflags" "256" "model" "*67" } { "classname" "item_health" "origin" "352 1464 -232" } { "spawnflags" "1" "origin" "352 1392 -232" "classname" "item_health" } { "classname" "item_armorInv" "origin" "744 1424 -448" } { "classname" "item_health" "origin" "-56 320 -232" } { "origin" "-16 320 -232" "classname" "item_health" } { "targetname" "t117" "classname" "trigger_teleport" "target" "t115" "spawnflags" "2" "model" "*68" } { "delay" ".5" "targetname" "t117" "classname" "trigger_teleport" "target" "t116" "spawnflags" "2" "model" "*69" } { "classname" "monster_wizard" "origin" "2928 1816 -152" "angle" "180" "targetname" "t117" } { "angle" "180" "origin" "2928 1768 -152" "classname" "monster_wizard" "targetname" "t117" } { "classname" "info_teleport_destination" "origin" "1824 1920 -184" "angle" "225" "targetname" "t115" } { "classname" "info_teleport_destination" "origin" "1880 1544 -184" "angle" "180" "targetname" "t116" } { "classname" "trigger_once" "target" "t117" "model" "*70" } { "classname" "monster_zombie" "origin" "764 388 -208" "angle" "0" "targetname" "t111" } { "angle" "0" "origin" "764 -12 -208" "classname" "monster_zombie" "targetname" "t111" } { "classname" "monster_zombie" "origin" "408 -56 -208" "angle" "270" "targetname" "t111" } { "classname" "light" "origin" "1200 672 -240" "light" "125" } { "classname" "item_spikes" "origin" "72 392 -64" "spawnflags" "1" } { "classname" "item_spikes" "origin" "2368 920 -224" } { "origin" "2032 976 -224" "classname" "item_spikes" } { "classname" "light" "origin" "1416 2096 -112" "light" "150" } { "light" "150" "origin" "1240 2096 -112" "classname" "light" } { "classname" "item_spikes" "origin" "464 1824 -240" } { "origin" "504 1824 -240" "classname" "item_spikes" } { "classname" "item_shells" "origin" "-96 1472 -232" "spawnflags" "1" } { "classname" "item_health" "origin" "528 -172 -232" } { "classname" "item_health" "origin" "40 -64 -64" } { "light" "225" "classname" "light_torch_small_walltorch" "origin" "122 -86 -8" } { "origin" "134 462 -8" "classname" "light_torch_small_walltorch" "light" "225" } { "light" "250" "origin" "678 446 92" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "678 -70 92" "light" "250" } { "light" "150" "origin" "120 -56 -16" "classname" "light" } { "classname" "light" "origin" "136 424 -16" "light" "150" } { "light" "150" "origin" "600 184 296" "classname" "light" } { "classname" "light" "origin" "152 184 296" "light" "150" } { "light" "150" "origin" "368 376 296" "classname" "light" } { "classname" "light" "origin" "368 0 296" "light" "150" } { "light" "150" "origin" "352 192 232" "classname" "light" } { "light" "200" "origin" "64 408 168" "classname" "light" } { "classname" "light" "origin" "56 -48 168" "light" "200" } { "light" "125" "origin" "1520 1880 24" "classname" "light" } { "origin" "272 272 -232" "classname" "item_rockets" } { "targetname" "t45" "classname" "func_door" "angle" "-2" "sounds" "1" "wait" "-1" "model" "*71" } { "classname" "light" "origin" "416 -152 -152" "light" "125" } { "targetname" "t45" "angle" "90" "origin" "416 -120 -208" "classname" "monster_zombie" "spawnflags" "256" } { "origin" "400 524 -232" "classname" "item_health" } { "light" "125" "origin" "416 536 -152" "classname" "light" } { "targetname" "t45" "wait" "-1" "sounds" "1" "angle" "-2" "classname" "func_door" "model" "*72" } { "targetname" "t45" "angle" "270" "origin" "416 496 -208" "classname" "monster_zombie" "spawnflags" "256" } { "target" "t120" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*73" } { "target" "t120" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*74" } { "targetname" "t120" "target" "t119" "classname" "trigger_counter" "model" "*75" } { "light" "125" "origin" "1792 840 -112" "classname" "light" } { "classname" "light" "origin" "1584 840 -112" "light" "125" } { "light" "125" "origin" "1792 2280 -480" "classname" "light" } { "classname" "light" "origin" "1792 2144 -480" "light" "125" } { "origin" "1776 2232 -508" "classname" "item_health" } { "classname" "item_health" "origin" "1776 2192 -508" } { "light" "150" "origin" "1016 1696 -336" "classname" "light" } { "light" "125" "origin" "1080 1696 -280" "classname" "light" } { "light" "125" "origin" "1152 1696 -200" "classname" "light" } { "light" "150" "origin" "1096 1696 -352" "classname" "light" } { "classname" "trigger_secret" "model" "*76" } { "target" "t116" "classname" "trigger_teleport" "model" "*77" } { "spawnflags" "768" "angle" "315" "origin" "1400 1856 -176" "classname" "monster_ogre" } { "target" "t121" "targetname" "t122" "spawnflags" "768" "origin" "1824 2280 -344" "classname" "path_corner" } { "target" "t122" "targetname" "t121" "spawnflags" "768" "classname" "path_corner" "origin" "2080 2280 -344" } { "target" "t121" "spawnflags" "769" "angle" "180" "origin" "2128 2272 -328" "classname" "monster_demon1" } { "spawnflags" "2816" "origin" "1824 2072 -352" "classname" "item_shells" } { "spawnflags" "769" "angle" "90" "origin" "1792 2176 -144" "classname" "monster_wizard" } { "spawnflags" "769" "angle" "180" "origin" "2600 1640 -200" "classname" "monster_hell_knight" } { "spawnflags" "2816" "origin" "2096 1136 -32" "classname" "item_shells" } { "classname" "monster_wizard" "origin" "1872 1432 -72" "angle" "90" "spawnflags" "769" } { "classname" "monster_hell_knight" "origin" "2400 1032 -8" "angle" "180" "spawnflags" "769" } { "classname" "monster_demon1" "origin" "1000 496 -104" "angle" "0" "spawnflags" "768" } { "classname" "monster_demon1" "origin" "1240 2088 -168" "angle" "45" "spawnflags" "769" "targetname" "t110" } { "classname" "monster_hell_knight" "origin" "360 1936 -208" "angle" "270" "spawnflags" "769" "targetname" "t114" } { "classname" "item_shells" "origin" "16 1768 -232" "spawnflags" "2560" } { "spawnflags" "2560" "origin" "344 1576 -232" "classname" "item_shells" } { "classname" "trigger_changelevel" "map" "e2m4" "model" "*78" } { "classname" "light" "origin" "1136 -1144 264" "light" "250" } { "light" "250" "origin" "1264 -552 44" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "1008 -552 44" "light" "250" } { "classname" "monster_demon1" "origin" "888 -120 56" "angle" "0" "spawnflags" "769" "targetname" "t66" } { "classname" "monster_hell_knight" "origin" "616 184 56" "angle" "0" "spawnflags" "768" } { "classname" "item_spikes" "origin" "880 216 32" "spawnflags" "2816" } { "classname" "monster_hell_knight" "origin" "1944 728 -8" "angle" "0" "spawnflags" "769" } { "classname" "light" "origin" "-48 1184 -156" "light" "200" "style" "10" } { "style" "10" "light" "200" "origin" "0 1024 -120" "classname" "light" } { "classname" "light" "origin" "48 800 -120" "light" "200" "style" "10" } { "style" "10" "light" "200" "origin" "0 600 -120" "classname" "light" } { "classname" "monster_hell_knight" "origin" "128 1088 -208" "angle" "225" "spawnflags" "1" } { "angle" "315" "origin" "-104 760 -208" "classname" "monster_hell_knight" "spawnflags" "1" } { "classname" "item_spikes" "origin" "-56 592 -232" } { "classname" "item_health" "origin" "-56 920 -232" } { "classname" "monster_demon1" "origin" "0 544 -208" "angle" "90" "target" "t123" "spawnflags" "769" } { "mangle" "20 315 0" "origin" "1568 2040 -88" "classname" "info_intermission" } { "classname" "item_shells" "origin" "1528 1968 -352" "spawnflags" "3584" } { "origin" "-88 1376 -232" "classname" "item_health" "spawnflags" "3585" } { "classname" "item_artifact_envirosuit" "origin" "1216 1696 -168" "spawnflags" "3584" } { "classname" "monster_demon1" "origin" "144 372 -208" "angle" "180" "spawnflags" "768" "targetname" "t123" } { "classname" "monster_demon1" "origin" "0 528 -208" "angle" "90" "spawnflags" "1025" } { "classname" "info_player_deathmatch" "origin" "1128 -840 -80" "angle" "90" } { "classname" "info_player_deathmatch" "origin" "656 184 -208" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "-24 1440 -208" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "1240 1816 -168" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "1032 1568 -168" "angle" "0" } { "classname" "func_wall" "spawnflags" "1792" "model" "*79" } { "classname" "weapon_rocketlauncher" "origin" "184 1440 -232" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "1424 608 -104" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "2272 680 -8" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "2240 1472 -200" "angle" "270" } { "classname" "weapon_supernailgun" "origin" "2236 1184 -32" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "2424 1824 -200" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "1792 2072 -328" "angle" "270" } { "classname" "weapon_supershotgun" "origin" "1488 1584 -200" "spawnflags" "1792" } { "classname" "weapon_grenadelauncher" "origin" "88 184 -64" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "1224 840 -168" "angle" "90" } { "classname" "weapon_nailgun" "origin" "1024 872 -152" "spawnflags" "1792" } { "classname" "weapon_supershotgun" "origin" "136 1760 -232" "spawnflags" "1792" } { "classname" "weapon_nailgun" "origin" "1976 2288 -352" "spawnflags" "1792" } { "classname" "weapon_lightning" "origin" "2128 1792 -352" "spawnflags" "1792" } { "classname" "item_cells" "origin" "1608 728 -128" "spawnflags" "1792" } { "spawnflags" "1792" "classname" "item_cells" "origin" "72 1032 -232" } { "classname" "item_cells" "origin" "1008 1328 -192" "spawnflags" "1792" } { "classname" "item_cells" "origin" "1304 -1160 -96" "spawnflags" "1792" } { "origin" "2272 1440 -224" "classname" "item_shells" "spawnflags" "2816" } { "origin" "224 1736 -232" "classname" "item_health" } { "classname" "info_intermission" "origin" "1328 -1168 192" "mangle" "20 120 0" } { "classname" "info_intermission" "origin" "1248 680 8" "mangle" "20 130 0" } { "classname" "info_intermission" "origin" "1280 1824 -104" "mangle" "10 180 0" } { "classname" "light" "origin" "-304 888 -80" "light" "150" } { "light" "150" "origin" "-304 712 -80" "classname" "light" } { "classname" "light" "origin" "-224 872 -8" "light" "125" } { "classname" "light" "origin" "-224 728 -8" "light" "125" } { "light" "150" "origin" "-178 706 -156" "classname" "light_torch_small_walltorch" } { "classname" "light" "origin" "-320 838 -138" "light" "100" } { "light" "100" "origin" "-320 774 -138" "classname" "light" } { "classname" "info_player_coop" "origin" "1192 -1088 -72" "angle" "90" } { "angle" "90" "origin" "1080 -1088 -72" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "1008 -1112 -72" "angle" "90" } { "angle" "90" "origin" "1264 -1112 -72" "classname" "info_player_coop" } { "classname" "item_armor1" "origin" "784 1816 -232" } { "classname" "item_spikes" "origin" "-56 1472 -232" "spawnflags" "1" } { "classname" "item_rockets" "origin" "400 -172 -232" } { "classname" "func_wall" "spawnflags" "1792" "model" "*80" } { "spawnflags" "1792" "classname" "func_wall" "model" "*81" } { "classname" "path_corner" "origin" "1954 1770 -96" "targetname" "t124" "target" "t125" } { "classname" "path_corner" "origin" "1954 1770 -320" "targetname" "t125" "target" "t124" } { "classname" "weapon_grenadelauncher" "origin" "1688 720 -128" "spawnflags" "2048" } { "wait" "-1" "angle" "-2" "classname" "func_door" "targetname" "t126" "lip" "-8" "model" "*82" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "model" "*83" } { "classname" "light" "origin" "-224 832 -152" "light" "125" } { "classname" "trigger_counter" "target" "t126" "targetname" "t127" "spawnflags" "1" "count" "7" "model" "*84" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*85" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*86" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*87" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*88" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*89" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*90" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*91" } { "classname" "ambient_swamp1" "origin" "1338 -854 -104" } { "classname" "ambient_swamp2" "origin" "938 -854 -104" } { "classname" "ambient_drip" "origin" "1138 -854 -176" } { "classname" "ambient_drip" "origin" "1650 -862 -192" } { "classname" "ambient_drip" "origin" "1674 -438 -192" } { "classname" "ambient_drip" "origin" "1682 2 -48" } { "classname" "ambient_swamp1" "origin" "1674 1986 -280" } { "classname" "ambient_swamp2" "origin" "1826 2378 -280" } { "classname" "ambient_swamp1" "origin" "2258 2058 -280" } { "classname" "ambient_drip" "origin" "746 1370 -376" } { "classname" "ambient_drip" "origin" "762 906 -240" } { "origin" "1034 722 -240" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "554 1818 -352" } { "origin" "1002 1810 -352" "classname" "ambient_drip" } { "speed" "35" "classname" "func_door" "wait" "-1" "angle" "-2" "sounds" "1" "targetname" "t101" "model" "*92" } { "classname" "light" "origin" "1440 296 -80" "light" "125" } { "origin" "1792 792 -240" "classname" "item_spikes" } �������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e1m2.ent.orig����������������������������������������������������0000644�0000000�0000000�00000120332�12403131422�017766� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "message" "Castle of the Damned" "wad" "gfx/wizard.wad" "classname" "worldspawn" "worldtype" "0" "sounds" "8" } { "angle" "270" "origin" "1496 1664 296" "classname" "info_player_start" } { "origin" "1432 672 336" "classname" "light" "light" "250" } { "light" "200" "origin" "1496 888 272" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "932 640 340" } { "classname" "light_torch_small_walltorch" "origin" "1104 812 340" } { "classname" "light" "origin" "1104 640 544" "light" "300" } { "light" "175" "origin" "1216 536 353" "classname" "light" } { "light" "250" "origin" "1816 328 448" "classname" "light" } { "light" "200" "origin" "1632 472 208" "classname" "light" } { "light" "200" "origin" "1792 -392 240" "classname" "light" } { "light" "200" "origin" "1452 -124 508" "classname" "light" } { "light" "150" "origin" "1196 -124 508" "classname" "light" } { "light" "150" "origin" "1044 -124 508" "classname" "light" } { "light" "200" "origin" "756 -124 508" "classname" "light" } { "light" "250" "origin" "744 336 145" "classname" "light" } { "light" "200" "origin" "1176 -912 672" "classname" "light" } { "origin" "1328 -544 552" "classname" "light" } { "classname" "light" "origin" "1528 -912 640" "light" "200" } { "light" "200" "classname" "light" "origin" "880 -648 672" } { "origin" "240 -264 392" "classname" "light" "light" "250" } { "classname" "light" "origin" "-352 -504 464" "light" "200" } { "origin" "-448 -608 804" "classname" "light" "light" "450" } { "light" "250" "origin" "776 -912 472" "classname" "light" } { "light" "300" "origin" "1630 -806 428" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "1528 -912 464" "classname" "light" } { "classname" "light" "origin" "1180 -484 560" } { "classname" "light" "origin" "1184 -612 560" } { "classname" "light" "origin" "1016 -368 472" "light" "100" } { "classname" "light" "origin" "1016 -464 472" "light" "100" } { "classname" "light" "origin" "1020 -560 472" "light" "100" } { "classname" "light" "origin" "1208 -776 472" "light" "100" } { "classname" "light" "origin" "1288 -776 472" "light" "100" } { "classname" "light" "origin" "1360 -776 472" "light" "100" } { "light" "200" "origin" "1792 120 376" "classname" "light" } { "origin" "1538 182 356" "classname" "light_torch_small_walltorch" } { "light" "200" "origin" "1640 80 360" "classname" "light" } { "light" "200" "origin" "1928 80 360" "classname" "light" } { "light" "250" "origin" "1792 296 208" "classname" "light" } { "light" "150" "origin" "1800 40 160" "classname" "light" } { "light" "200" "origin" "1776 -392 160" "classname" "light" } { "light" "200" "origin" "1304 -392 152" "classname" "light" } { "light" "250" "origin" "1632 112 136" "classname" "light" } { "light" "250" "origin" "1432 312 136" "classname" "light" } { "light" "200" "origin" "1136 -656 160" "classname" "light" } { "light" "200" "origin" "1136 -416 160" "classname" "light" } { "light" "250" "origin" "1448 -552 160" "classname" "light" } { "light" "200" "origin" "1920 440 136" "classname" "light" } { "light" "200" "origin" "968 88 177" "classname" "light" } { "light" "300" "origin" "1088 312 129" "classname" "light" } { "light" "150" "origin" "1376 168 129" "classname" "light" } { "light" "250" "origin" "112 -384 392" "classname" "light" } { "origin" "300 -1004 508" "classname" "light" } { "origin" "296 -812 505" "classname" "light" } { "origin" "300 -1204 505" "classname" "light" } { "light" "150" "origin" "470 -1006 468" "classname" "light_torch_small_walltorch" } { "light" "250" "origin" "984 -1216 496" "classname" "light" } { "light" "250" "origin" "888 -1128 552" "classname" "light" } { "light" "200" "origin" "800 -1216 592" "classname" "light" } { "light" "200" "origin" "664 -1216 592" "classname" "light" } { "light" "200" "origin" "584 -1136 592" "classname" "light" } { "light" "200" "origin" "584 -968 592" "classname" "light" } { "light" "250" "origin" "584 -744 592" "classname" "light" } { "light" "200" "origin" "528 -1144 464" "classname" "light" } { "light" "200" "origin" "528 -856 464" "classname" "light" } { "light" "200" "classname" "light" "origin" "1496 1544 440" } { "origin" "1384 1392 440" "classname" "light" "light" "250" } { "origin" "1496 1104 520" "classname" "light" } { "origin" "1608 1400 440" "classname" "light" "light" "250" } { "light" "250" "origin" "1240 1712 360" "classname" "light" } { "light" "250" "origin" "1744 1696 360" "classname" "light" } { "classname" "light" "origin" "1384 1136 440" "light" "250" } { "classname" "light" "origin" "1608 1144 440" "light" "250" } { "classname" "path_corner" "origin" "1168 736 296" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "992 744 296" "targetname" "t6" "target" "t7" } { "classname" "path_corner" "origin" "1000 544 296" "targetname" "t7" "target" "t34" } { "classname" "item_health" "origin" "960 704 288" } { "classname" "item_shells" "origin" "952 512 288" } { "classname" "path_corner" "origin" "1344 -128 304" "targetname" "t9" "target" "t8" } { "classname" "path_corner" "origin" "898 -128 304" "targetname" "t8" "target" "t9" } { "spawnflags" "1" "classname" "monster_ogre" "origin" "1018 -126 320" "angle" "0" "target" "t8" } { "classname" "item_health" "origin" "1344 -224 296" "spawnflags" "1" } { "classname" "item_health" "origin" "1400 -224 296" "spawnflags" "1" } { "origin" "1528 192 296" "classname" "item_shells" } { "classname" "path_corner" "origin" "1496 1040 184" "targetname" "t22" "target" "t23" } { "classname" "path_corner" "origin" "1496 840 248" "targetname" "t23" "target" "t33" } { "spawnflags" "1" "classname" "item_shells" "origin" "1056 -648 288" } { "classname" "item_health" "origin" "1184 -736 288" } { "spawnflags" "257" "classname" "monster_army" "origin" "1646 -698 360" "angle" "180" "targetname" "t89" } { "classname" "path_corner" "origin" "1400 640 272" "targetname" "t30" "target" "t79" } { "classname" "path_corner" "origin" "1496 752 232" "targetname" "t33" "target" "t77" } { "classname" "path_corner" "origin" "1192 560 296" "targetname" "t34" "target" "t80" } { "classname" "item_shells" "origin" "1616 1280 176" } { "classname" "item_health" "origin" "1056 -840 416" "spawnflags" "1" } { "classname" "item_health" "origin" "1104 -840 416" "spawnflags" "1" } { "spawnflags" "1" "classname" "monster_army" "origin" "262 -458 320" "angle" "0" "target" "t96" } { "spawnflags" "1024" "classname" "item_health" "origin" "136 -296 296" } { "classname" "path_corner" "origin" "-536 -704 472" "targetname" "t42" "target" "t41" } { "classname" "path_corner" "origin" "-576 -416 472" "targetname" "t41" "target" "t42" } { "classname" "monster_knight" "origin" "-578 -654 480" "target" "t41" "spawnflags" "1" } { "classname" "item_shells" "origin" "-368 -752 456" } { "classname" "item_health" "origin" "-16 -520 360" "spawnflags" "1" } { "classname" "item_health" "origin" "-16 -576 360" "spawnflags" "1" } { "classname" "light" "origin" "1848 -568 320" "light" "200" } { "classname" "light" "origin" "1760 -560 408" "light" "200" } { "classname" "light" "origin" "1624 -560 352" "light" "150" } { "targetname" "t43" "angle" "270" "origin" "800 368 312" "classname" "info_teleport_destination" } { "origin" "752 168 296" "classname" "item_health" } { "target" "t43" "classname" "trigger_teleport" "model" "*1" } { "origin" "1712 -568 256" "classname" "item_health" } { "classname" "monster_ogre" "origin" "1494 1134 208" "angle" "270" "target" "t22" } { "light" "300" "origin" "1856 1288 384" "classname" "light" } { "classname" "light" "origin" "1136 1288 384" } { "light" "200" "origin" "1920 328 380" "classname" "light" } { "target" "t122" "spawnflags" "2048" "sounds" "1" "classname" "item_key1" "origin" "880 -300 464" } { "light" "300" "origin" "648 -384 430" "classname" "light_flame_small_yellow" } { "light" "250" "classname" "light_flame_small_yellow" "origin" "1104 -224 406" } { "light" "250" "origin" "1456 -128 406" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "988 532 353" "light" "175" } { "light" "125" "origin" "1100 648 328" "classname" "light" } { "origin" "1616 936 310" "classname" "light_flame_small_yellow" "light" "300" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "1360 936 310" } { "origin" "1792 504 390" "classname" "light_flame_small_yellow" "light" "300" } { "origin" "1972 -252 332" "classname" "info_null" "targetname" "t47" } { "light" "800" "origin" "1992 -252 336" "classname" "light" "target" "t47" } { "classname" "info_null" "origin" "1948 -292 332" "targetname" "t48" } { "light" "800" "classname" "light" "origin" "1948 -312 336" "target" "t48" } { "origin" "880 -328 562" "classname" "light_flame_small_yellow" "light" "300" } { "classname" "light" "origin" "1056 -1288 504" } { "origin" "1184 -1288 504" "classname" "light" } { "classname" "light" "origin" "1312 -1288 504" } { "origin" "1440 -1288 504" "classname" "light" } { "sounds" "1" "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t50" "model" "*2" } { "sounds" "1" "classname" "func_door" "wait" "-1" "angle" "-2" "targetname" "t50" "model" "*3" } { "classname" "trigger_once" "target" "t50" "model" "*4" } { "classname" "light" "origin" "1368 -1016 504" "light" "200" } { "light" "200" "origin" "1120 -1024 504" "classname" "light" } { "classname" "light" "origin" "1248 -1184 464" "light" "175" } { "classname" "light" "origin" "776 -480 480" "light" "225" } { "classname" "light" "origin" "1904 -144 168" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "1706 -206 316" "light" "300" } { "light" "300" "origin" "2134 -34 316" "classname" "light_torch_small_walltorch" } { "origin" "1152 -296 422" "classname" "light_flame_small_yellow" "light" "250" } { "light" "250" "classname" "light_flame_small_yellow" "origin" "1152 -760 422" } { "origin" "1528 -556 478" "classname" "light_flame_small_yellow" "light" "250" } { "targetname" "t52" "origin" "1532 -552 328" "classname" "info_null" } { "origin" "1340 -544 384" "classname" "item_armor2" } { "sounds" "1" "targetname" "t53" "lip" "64" "wait" "-1" "angle" "-1" "classname" "func_door" "model" "*5" } { "sounds" "1" "targetname" "t53" "classname" "func_door" "angle" "-1" "wait" "-1" "lip" "64" "model" "*6" } { "targetname" "t53" "target" "t54" "classname" "trigger_teleport" "spawnflags" "2" "model" "*7" } { "targetname" "t54" "angle" "180" "origin" "1408 -688 449" "classname" "info_teleport_destination" } { "targetname" "t53" "target" "t57" "classname" "trigger_teleport" "spawnflags" "2" "model" "*8" } { "targetname" "t57" "angle" "180" "origin" "1408 -400 361" "classname" "info_teleport_destination" } { "spawnflags" "768" "targetname" "t53" "angle" "180" "origin" "1912 -856 217" "classname" "monster_wizard" } { "spawnflags" "768" "targetname" "t53" "classname" "monster_wizard" "origin" "1912 -936 217" "angle" "180" } { "targetname" "t50" "angle" "90" "origin" "1320 -1112 441" "classname" "monster_knight" } { "spawnflags" "256" "targetname" "t50" "angle" "0" "origin" "1056 -1144 441" "classname" "monster_knight" } { "sounds" "1" "targetname" "t61" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*9" } { "sounds" "3" "lip" "64" "spawnflags" "1" "targetname" "t58" "angle" "270" "wait" "-1" "classname" "func_door" "model" "*10" } { "sounds" "1" "wait" "-1" "angle" "270" "target" "t58" "classname" "func_button" "model" "*11" } { "target" "t61" "classname" "trigger_once" "model" "*12" } { "light" "225" "origin" "984 -480 480" "classname" "light" } { "light" "175" "origin" "880 -368 176" "classname" "light" } { "classname" "light" "origin" "880 -592 240" "light" "175" } { "light" "200" "origin" "880 -488 184" "classname" "light" } { "light" "150" "origin" "880 -304 472" "classname" "light" } { "classname" "light" "origin" "-96 308 864" "light" "850" } { "origin" "-32 -440 624" "classname" "light" } { "sounds" "1" "targetname" "t73" "wait" "-1" "lip" "196" "angle" "-1" "classname" "func_door" "model" "*13" } { "light" "300" "origin" "104 144 688" "classname" "light" } { "classname" "light" "origin" "-264 144 688" "light" "300" } { "sounds" "1" "targetname" "t73" "wait" "-1" "classname" "func_door" "angle" "-1" "lip" "196" "model" "*14" } { "classname" "light_flame_small_yellow" "origin" "-24 -232 414" "light" "250" } { "lip" "-2" "sounds" "3" "speed" "350" "targetname" "t73" "angle" "180" "wait" "-1" "classname" "func_door" "model" "*15" } { "target" "t63" "targetname" "t62" "origin" "-12 312 264" "classname" "path_corner" } { "target" "t64" "targetname" "t63" "origin" "-12 312 356" "classname" "path_corner" } { "wait" "-1" "target" "t66" "targetname" "t64" "classname" "path_corner" "origin" "-13 440 355" } { "sounds" "1" "targetname" "t71" "wait" "-1" "target" "t65" "angle" "-2" "classname" "func_button" "model" "*16" } { "target" "t64" "targetname" "t66" "origin" "-13 440 355" "classname" "path_corner" } { "light" "200" "origin" "-96 440 376" "classname" "light" } { "light" "150" "origin" "8 456 376" "classname" "light" } { "targetname" "t70" "target" "t67" "classname" "path_corner" "origin" "-220 312 264" } { "target" "t68" "targetname" "t67" "classname" "path_corner" "origin" "-220 312 356" } { "wait" "-1" "target" "t69" "targetname" "t68" "origin" "-221 440 355" "classname" "path_corner" } { "target" "t68" "targetname" "t69" "classname" "path_corner" "origin" "-221 440 355" } { "classname" "light" "origin" "-200 456 376" "light" "150" } { "targetname" "t65" "target" "t62" "classname" "func_train" "speed" "50" "sounds" "1" "model" "*17" } { "light" "250" "origin" "-96 632 406" "classname" "light_flame_small_yellow" } { "targetname" "t72" "origin" "-96 288 304" "classname" "info_null" } { "light" "450" "target" "t72" "origin" "-96 288 368" "classname" "light" } { "target" "t70" "targetname" "t65" "speed" "50" "classname" "func_train" "sounds" "1" "model" "*18" } { "lip" "-2" "sounds" "0" "speed" "350" "classname" "func_door" "wait" "-1" "angle" "0" "model" "*19" } { "targetname" "t65" "delay" "4.7" "target" "t73" "classname" "trigger_once" "model" "*20" } { "targetname" "t73" "angle" "270" "origin" "-96 552 320" "classname" "monster_demon1" "spawnflags" "1024" } { "targetname" "t74" "angle" "90" "origin" "132 -192 476" "classname" "info_teleport_destination" } { "targetname" "t75" "classname" "info_teleport_destination" "origin" "-328 -196 476" "angle" "90" } { "target" "t75" "classname" "trigger_teleport" "spawnflags" "1" "model" "*21" } { "target" "t74" "classname" "trigger_teleport" "spawnflags" "1" "model" "*22" } { "light" "200" "origin" "-418 306 356" "classname" "light" } { "classname" "light" "origin" "260 308 356" "light" "200" } { "sounds" "0" "targetname" "t73" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*23" } { "sounds" "0" "targetname" "t73" "wait" "-1" "angle" "0" "classname" "func_door" "model" "*24" } { "sounds" "0" "wait" "-1" "angle" "0" "targetname" "t73" "classname" "func_door" "model" "*25" } { "sounds" "0" "targetname" "t73" "angle" "180" "wait" "-1" "classname" "func_door" "model" "*26" } { "sounds" "3" "wait" "-1" "angle" "-2" "targetname" "t73" "classname" "func_door" "model" "*27" } { "classname" "light" "origin" "-96 24 360" "light" "100" } { "light" "100" "origin" "-96 -40 360" "classname" "light" } { "classname" "light" "origin" "-160 -568 624" } { "origin" "-160 -440 624" "classname" "light" } { "classname" "light" "origin" "-32 -568 624" } { "classname" "light" "origin" "-96 -88 484" "light" "150" } { "classname" "light" "origin" "-440 -408 804" "light" "450" } { "classname" "light" "origin" "600 -128 352" "light" "200" } { "classname" "light" "origin" "576 -608 504" "light" "250" } { "classname" "light" "origin" "384 -504 392" "light" "250" } { "classname" "light" "origin" "1264 240 295" "light" "250" } { "light" "250" "origin" "944 240 295" "classname" "light" } { "classname" "path_corner" "origin" "1480 704 264" "targetname" "t77" "target" "t78" } { "classname" "path_corner" "origin" "1448 656 264" "targetname" "t78" "target" "t30" } { "classname" "path_corner" "origin" "1264 640 304" "targetname" "t80" "target" "t5" } { "classname" "path_corner" "origin" "1328 640 304" "targetname" "t79" "target" "t80" } { "light" "200" "origin" "1488 -392 216" "classname" "light" } { "classname" "path_corner" "origin" "816 80 304" "targetname" "t83" "target" "t82" "spawnflags" "256" } { "origin" "816 312 304" "classname" "path_corner" "targetname" "t82" "target" "t83" "spawnflags" "256" } { "classname" "monster_army" "origin" "806 206 320" "angle" "90" "target" "t82" "spawnflags" "256" } { "classname" "trigger_once" "target" "t84" "model" "*28" } { "classname" "monster_ogre" "origin" "1790 -146 312" "angle" "90" "targetname" "t84" } { "classname" "path_corner" "origin" "1088 -672 296" "target" "t85" "targetname" "t88" } { "origin" "1088 -376 296" "classname" "path_corner" "targetname" "t85" "target" "t86" } { "classname" "path_corner" "origin" "1088 -376 296" "targetname" "t87" "target" "t88" } { "origin" "1448 -376 296" "classname" "path_corner" "targetname" "t86" "target" "t87" } { "spawnflags" "1" "classname" "monster_ogre" "origin" "1086 -498 312" "angle" "270" "target" "t88" } { "spawnflags" "256" "classname" "trigger_once" "target" "t89" "model" "*29" } { "classname" "item_health" "origin" "352 -752 408" "spawnflags" "1025" } { "spawnflags" "1025" "origin" "352 -792 408" "classname" "item_health" } { "classname" "item_health" "origin" "352 -832 408" "spawnflags" "1" } { "classname" "path_corner" "origin" "408 -776 416" "targetname" "t94" "target" "t95" } { "origin" "400 -1088 416" "classname" "path_corner" "targetname" "t95" "target" "t94" } { "classname" "path_corner" "origin" "584 -1096 416" "targetname" "t92" "target" "t93" } { "origin" "584 -792 416" "classname" "path_corner" "targetname" "t93" "target" "t92" } { "classname" "monster_army" "origin" "390 -970 432" "angle" "0" "target" "t94" } { "classname" "monster_army" "origin" "566 -970 432" "angle" "270" "target" "t92" } { "classname" "path_corner" "origin" "208 -304 304" "targetname" "t97" "target" "t96" } { "classname" "path_corner" "origin" "208 -464 304" "targetname" "t96" "target" "t97" } { "spawnflags" "1280" "classname" "path_corner" "origin" "-344 160 304" "targetname" "t100" "target" "t99" } { "spawnflags" "1280" "origin" "168 152 304" "classname" "path_corner" "targetname" "t99" "target" "t100" } { "spawnflags" "1280" "classname" "monster_ogre" "origin" "240 152 320" "angle" "180" "target" "t99" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "-392 80 320" "angle" "0" "targetname" "t101" } { "spawnflags" "768" "classname" "trigger_once" "target" "t101" "model" "*30" } { "classname" "item_health" "origin" "40 -16 464" } { "origin" "80 -48 464" "classname" "item_health" } { "origin" "520 -72 296" "classname" "item_shells" } { "spawnflags" "1" "origin" "-424 -216 296" "classname" "item_shells" } { "spawnflags" "769" "angle" "270" "origin" "880 -400 568" "classname" "monster_wizard" } { "light" "200" "origin" "432 176 152" "classname" "light" } { "light" "150" "origin" "432 -56 256" "classname" "light" } { "origin" "264 -96 300" "classname" "item_health" } { "classname" "item_health" "origin" "264 -140 300" } { "spawnflags" "1" "origin" "1184 1568 240" "classname" "item_health" } { "classname" "item_health" "origin" "1184 1616 240" "spawnflags" "1" } { "light" "150" "origin" "1496 1112 108" "classname" "light" } { "light" "200" "origin" "1120 1152 96" "classname" "light" } { "light" "200" "origin" "1080 692 184" "classname" "light" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "832 1184 294" } { "origin" "464 536 358" "classname" "light_flame_small_yellow" "light" "300" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "600 704 334" } { "light" "150" "origin" "1736 1096 110" "classname" "light" } { "light" "100" "origin" "832 1056 134" "classname" "light" } { "light" "150" "origin" "784 704 294" "classname" "light" } { "origin" "856 592 182" "classname" "item_health" } { "classname" "item_health" "origin" "824 552 182" } { "classname" "info_player_deathmatch" "origin" "-416 -144 320" "angle" "90" } { "classname" "info_player_deathmatch" "origin" "168 -480 320" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "1496 1328 200" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "1936 -136 312" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "936 -1216 432" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "792 -992 440" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "1080 -720 312" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "408 -752 432" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "792 -208 320" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "784 808 206" "angle" "225" } { "sounds" "3" "wait" "3" "angle" "90" "classname" "func_door" "model" "*31" } { "sounds" "0" "wait" "3" "angle" "270" "classname" "func_door" "model" "*32" } { "spawnflags" "1" "origin" "680 832 182" "classname" "item_shells" } { "origin" "1392 240 300" "classname" "weapon_supershotgun" } { "spawnflags" "769" "angle" "270" "origin" "954 -754 444" "classname" "monster_ogre" } { "spawnflags" "1" "origin" "520 -1280 408" "classname" "item_shells" } { "light" "200" "origin" "-612 -500 548" "classname" "light" } { "classname" "func_door" "angle" "90" "targetname" "t110" "wait" "-1" "model" "*33" } { "sounds" "3" "classname" "func_door" "angle" "270" "wait" "-1" "model" "*34" } { "classname" "trigger_once" "target" "t110" "model" "*35" } { "classname" "trigger_changelevel" "map" "e1m3" "model" "*36" } { "spawnflags" "1792" "origin" "680 728 184" "classname" "weapon_rocketlauncher" } { "spawnflags" "1792" "origin" "1496 1256 176" "classname" "weapon_nailgun" } { "angle" "180" "spawnflags" "1792" "origin" "-96 -496 360" "classname" "weapon_supernailgun" } { "spawnflags" "1794" "origin" "-112 -8 464" "classname" "item_health" } { "spawnflags" "1793" "origin" "-112 -568 360" "classname" "item_spikes" } { "spawnflags" "1792" "origin" "1616 1424 176" "classname" "item_spikes" } { "spawnflags" "1792" "classname" "item_spikes" "origin" "1656 1424 176" } { "spawnflags" "1792" "origin" "1696 1424 176" "classname" "item_spikes" } { "spawnflags" "768" "target" "t34" "angle" "315" "origin" "1070 646 312" "classname" "monster_ogre" } { "spawnflags" "768" "targetname" "t84" "angle" "90" "origin" "1624 88 376" "classname" "monster_wizard" } { "spawnflags" "768" "angle" "90" "targetname" "t84" "origin" "1866 -378 312" "classname" "monster_ogre" } { "angle" "45" "origin" "1088 -1096 440" "classname" "monster_knight" "targetname" "t50" } { "spawnflags" "768" "classname" "monster_knight" "origin" "1400 -1144 440" "angle" "90" "targetname" "t50" } { "spawnflags" "256" "target" "t111" "targetname" "t112" "origin" "896 -1216 416" "classname" "path_corner" } { "spawnflags" "256" "target" "t112" "targetname" "t111" "classname" "path_corner" "origin" "704 -1216 416" } { "spawnflags" "257" "target" "t111" "angle" "180" "origin" "758 -1218 432" "classname" "monster_army" } { "spawnflags" "768" "target" "t114" "targetname" "t113" "origin" "-96 -520 368" "classname" "path_corner" } { "spawnflags" "768" "target" "t113" "targetname" "t114" "origin" "-96 -152 304" "classname" "path_corner" } { "targetname" "t116" "spawnflags" "769" "target" "t113" "angle" "270" "origin" "-98 -194 320" "classname" "monster_ogre" } { "spawnflags" "1536" "origin" "1936 -96 289" "classname" "item_health" } { "spawnflags" "1025" "origin" "1040 -1200 417" "classname" "item_health" } { "spawnflags" "769" "target" "t117" "angle" "315" "origin" "-560 -312 592" "classname" "monster_wizard" } { "spawnflags" "768" "target" "t118" "targetname" "t117" "origin" "-528 -344 576" "classname" "path_corner" } { "spawnflags" "768" "target" "t117" "targetname" "t118" "origin" "-352 -656 576" "classname" "path_corner" } { "classname" "light" "origin" "1360 976 224" "light" "150" } { "light" "150" "origin" "1616 976 224" "classname" "light" } { "classname" "light" "origin" "1208 1296 368" "light" "250" } { "origin" "1784 1288 368" "classname" "light" "light" "250" } { "classname" "light" "origin" "1496 1664 336" "light" "250" } { "classname" "light" "origin" "1752 1176 112" "light" "150" } { "light" "200" "origin" "1776 976 112" "classname" "light" } { "classname" "light" "origin" "1216 976 112" "light" "200" } { "light" "150" "origin" "1224 1176 112" "classname" "light" } { "classname" "light" "origin" "1496 1432 520" "light" "250" } { "classname" "light" "origin" "1496 1304 264" "light" "200" } { "classname" "light" "origin" "1496 1432 288" "light" "200" } { "classname" "light" "origin" "1608 1120 88" "light" "150" } { "light" "150" "origin" "1384 1120 88" "classname" "light" } { "classname" "light" "origin" "1496 864 368" "light" "150" } { "light" "175" "origin" "980 764 353" "classname" "light" } { "classname" "light" "origin" "1228 764 353" "light" "175" } { "classname" "light" "origin" "1104 464 353" "light" "200" } { "classname" "light" "origin" "1104 -40 423" "light" "200" } { "light" "150" "origin" "1416 -128 367" "classname" "light" } { "classname" "light" "origin" "1104 -184 367" "light" "200" } { "classname" "light" "origin" "1184 56 423" "light" "150" } { "light" "150" "origin" "1024 56 423" "classname" "light" } { "classname" "light" "origin" "1272 -64 399" "light" "150" } { "light" "150" "origin" "888 -64 399" "classname" "light" } { "classname" "light" "origin" "1104 152 129" "light" "300" } { "classname" "light" "origin" "976 392 129" "light" "200" } { "classname" "light" "origin" "1104 656 120" } { "classname" "light" "origin" "896 712 144" "light" "200" } { "classname" "light" "origin" "640 704 280" "light" "200" } { "classname" "light" "origin" "464 496 296" "light" "150" } { "classname" "light" "origin" "888 1152 96" "light" "200" } { "classname" "light" "origin" "840 880 240" "light" "200" } { "classname" "light" "origin" "848 584 240" "light" "150" } { "classname" "light" "origin" "784 160 144" "light" "200" } { "classname" "light" "origin" "440 336 144" "light" "150" } { "light" "150" "origin" "584 336 144" "classname" "light" } { "classname" "light" "origin" "432 24 136" "light" "150" } { "classname" "light" "origin" "656 328 224" "light" "200" } { "classname" "light" "origin" "432 -128 312" "light" "200" } { "classname" "light" "origin" "600 -384 360" "light" "200" } { "origin" "520 -128 406" "classname" "light_flame_small_yellow" "light" "250" } { "classname" "light" "origin" "424 -320 352" "light" "200" } { "classname" "light" "origin" "664 -1216 472" "light" "150" } { "classname" "light" "origin" "336 -1208 504" "light" "150" } { "light" "150" "origin" "336 -1008 504" "classname" "light" } { "classname" "light" "origin" "336 -816 504" "light" "150" } { "classname" "light" "origin" "880 -1000 496" "light" "200" } { "classname" "light" "origin" "880 -792 496" "light" "200" } { "classname" "light" "origin" "880 -376 304" "light" "200" } { "classname" "light" "origin" "1048 -912 480" "light" "225" } { "classname" "light" "origin" "1120 -1192 468" "light" "150" } { "light" "150" "origin" "1376 -1192 468" "classname" "light" } { "classname" "light" "origin" "1472 -912 464" "light" "175" } { "classname" "light" "origin" "880 -304 480" "light" "100" } { "classname" "light" "origin" "880 -680 480" "light" "175" } { "classname" "light" "origin" "1600 -704 484" "light" "150" } { "classname" "light" "origin" "1504 -704 348" "light" "175" } { "light" "175" "origin" "1336 -704 348" "classname" "light" } { "classname" "light" "origin" "1152 -640 332" "light" "200" } { "classname" "light" "origin" "1096 -552 348" "light" "150" } { "light" "200" "origin" "1160 -456 332" "classname" "light" } { "light" "150" "origin" "1216 -384 348" "classname" "light" } { "classname" "light" "origin" "1344 -384 348" "light" "150" } { "classname" "light" "origin" "1544 392 156" "light" "225" } { "light" "225" "origin" "1848 248 156" "classname" "light" } { "classname" "light" "origin" "1936 136 156" "light" "225" } { "light" "200" "origin" "2096 -80 156" "classname" "light" } { "light" "200" "origin" "2048 -408 156" "classname" "light" } { "classname" "light" "origin" "1456 -392 444" "light" "225" } { "classname" "light" "origin" "1640 -384 352" "light" "225" } { "classname" "light_torch_small_walltorch" "origin" "2134 -474 316" "light" "250" } { "light" "200" "origin" "168 216 496" "classname" "light" } { "classname" "light" "origin" "-328 208 496" "light" "200" } { "light" "200" "origin" "-96 360 432" "classname" "light" } { "classname" "light" "origin" "-96 144 432" "light" "200" } { "light" "200" "origin" "-376 32 432" "classname" "light" } { "light" "200" "origin" "208 -72 432" "classname" "light" } { "light" "150" "origin" "-96 72 360" "classname" "light" } { "light" "150" "origin" "-64 -232 368" "classname" "light" } { "light" "150" "origin" "-96 -320 560" "classname" "light" } { "light" "250" "origin" "-96 -496 448" "classname" "light" } { "light" "150" "origin" "-416 -104 392" "classname" "light" } { "light" "150" "origin" "-344 -152 528" "classname" "light" } { "classname" "light" "origin" "160 -152 528" "light" "150" } { "light" "150" "origin" "-96 8 528" "classname" "light" } { "light" "200" "origin" "-560 -504 688" "classname" "light" } { "classname" "light" "origin" "-440 -368 688" "light" "200" } { "light" "200" "origin" "-440 -656 688" "classname" "light" } { "classname" "light" "origin" "-336 -504 688" "light" "200" } { "classname" "light" "origin" "2084 -208 336" "light" "100" } { "light" "100" "origin" "2012 -252 332" "classname" "light" } { "classname" "light" "origin" "1948 -328 332" "light" "100" } { "light" "150" "origin" "1892 -452 332" "classname" "light" } { "sounds" "1" "targetname" "t120" "wait" "-1" "angle" "-2" "classname" "func_door" "lip" "4" "model" "*37" } { "target" "t120" "classname" "trigger_once" "model" "*38" } { "light" "100" "origin" "2076 -312 336" "classname" "light" } { "sounds" "3" "spawnflags" "2064" "angle" "0" "wait" "-1" "classname" "func_door" "model" "*39" } { "spawnflags" "2064" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*40" } { "light" "100" "origin" "332 -264 356" "classname" "light" } { "classname" "light" "origin" "144 -264 356" "light" "100" } { "light" "100" "origin" "1104 572 316" "classname" "light" } { "target" "t121" "wait" ".8" "classname" "trigger_multiple" "model" "*41" } { "targetname" "t121" "angle" "180" "origin" "2120 -256 332" "classname" "trap_spikeshooter" "spawnflags" "1024" } { "targetname" "t121" "angle" "90" "origin" "1944 -456 332" "classname" "trap_spikeshooter" "spawnflags" "1024" } { "light" "150" "origin" "1312 -856 472" "classname" "light" } { "classname" "light" "origin" "1184 -856 472" "light" "175" } { "classname" "light" "origin" "1560 -568 224" "light" "200" } { "classname" "func_door" "angle" "-2" "wait" "-1" "speed" "50" "sounds" "1" "targetname" "t123" "lip" "6" "model" "*42" } { "classname" "trigger_once" "target" "t123" "model" "*43" } { "classname" "light" "origin" "1496 -552 330" "light" "700" "target" "t52" } { "classname" "light" "origin" "1288 80 140" "light" "250" } { "classname" "light" "origin" "1288 400 80" "light" "200" } { "classname" "light" "origin" "1328 -664 160" "light" "200" } { "classname" "item_armor1" "origin" "784 56 304" } { "classname" "light" "origin" "1544 464 352" "light" "75" } { "classname" "func_plat" "model" "*44" } { "classname" "light" "origin" "1496 1192 280" "light" "200" } { "classname" "light" "origin" "1608 1192 136" "light" "100" } { "light" "100" "origin" "1384 1184 136" "classname" "light" } { "light" "100" "origin" "1608 1048 136" "classname" "light" } { "classname" "light" "origin" "1384 1048 136" "light" "100" } { "classname" "light" "origin" "1200 1148 92" "light" "150" } { "light" "150" "origin" "876 -184 367" "classname" "light" } { "classname" "light" "origin" "768 -128 384" "light" "200" } { "classname" "light" "origin" "1104 388 552" "light" "250" } { "light" "200" "origin" "1392 240 384" "classname" "light" } { "classname" "light" "origin" "1392 80 368" "light" "200" } { "classname" "light" "origin" "1272 400 367" "light" "150" } { "light" "150" "origin" "920 400 367" "classname" "light" } { "classname" "light" "origin" "816 208 368" "light" "200" } { "classname" "light" "origin" "800 24 368" "light" "200" } { "classname" "light" "origin" "800 376 385" "light" "150" } { "light" "150" "origin" "1400 400 385" "classname" "light" } { "classname" "path_corner" "origin" "1104 336 300" "target" "t126" "targetname" "t127" } { "origin" "1104 24 300" "classname" "path_corner" "targetname" "t126" "target" "t127" } { "classname" "monster_army" "origin" "1104 424 316" "angle" "270" "target" "t127" } { "targetname" "t128" "origin" "1392 240 308" "classname" "info_null" } { "light" "300" "target" "t128" "origin" "1392 240 376" "classname" "light" } { "targetname" "t129" "angle" "0" "origin" "552 -128 320" "classname" "monster_army" } { "target" "t129" "classname" "trigger_once" "model" "*45" } { "sounds" "1" "classname" "trigger_secret" "model" "*46" } { "sounds" "1" "classname" "trigger_secret" "model" "*47" } { "classname" "light" "origin" "1104 24 536" "light" "350" } { "spawnflags" "1" "classname" "func_door_secret" "angle" "270" "model" "*48" } { "light" "200" "origin" "1680 1552 320" "classname" "light" } { "classname" "light" "origin" "1312 1552 320" "light" "200" } { "classname" "item_spikes" "origin" "1480 1104 68" "spawnflags" "1" } { "classname" "item_spikes" "origin" "1760 -568 256" "spawnflags" "1" } { "classname" "item_spikes" "origin" "1232 -1200 416" } { "message" "This door is opened elsewhere..." "classname" "func_door" "sounds" "3" "angle" "180" "wait" "-1" "targetname" "t122" "speed" "35" "spawnflags" "2048" "model" "*49" } { "classname" "func_door" "angle" "0" "wait" "-1" "speed" "30" "spawnflags" "2048" "model" "*50" } { "classname" "light" "origin" "1496 1600 296" "light" "150 " } { "light" "150" "origin" "1568 1664 296" "classname" "light" } { "classname" "light" "origin" "1424 1664 296" "light" "150" } { "classname" "light" "origin" "1328 1424 296" "light" "200" } { "light" "250" "origin" "1696 1416 296" "classname" "light" } { "classname" "monster_army" "origin" "1592 1296 200" "angle" "270" } { "spawnflags" "768" "classname" "monster_demon1" "origin" "-96 576 320" "angle" "270" "targetname" "t73" "target" "t143" } { "classname" "path_corner" "origin" "1392 416 304" "targetname" "t131" "target" "t130" "spawnflags" "768" } { "origin" "1392 296 304" "classname" "path_corner" "targetname" "t130" "target" "t131" "spawnflags" "768" } { "classname" "monster_army" "origin" "1392 352 320" "angle" "270" "target" "t130" "spawnflags" "768" } { "target" "t132" "targetname" "t133" "origin" "296 -328 304" "classname" "path_corner" } { "target" "t133" "targetname" "t132" "classname" "path_corner" "origin" "472 -416 304" } { "spawnflags" "1" "target" "t132" "angle" "90" "origin" "472 -456 320" "classname" "monster_army" } { "spawnflags" "1" "targetname" "t89" "angle" "135" "origin" "1712 -784 376" "classname" "monster_army" } { "target" "t135" "spawnflags" "256" "targetname" "t134" "origin" "400 -1128 416" "classname" "path_corner" } { "target" "t134" "spawnflags" "256" "targetname" "t135" "classname" "path_corner" "origin" "400 -1248 416" } { "target" "t134" "spawnflags" "257" "angle" "90" "origin" "408 -1208 432" "classname" "monster_army" } { "targetname" "t101" "angle" "90" "origin" "-288 -24 488" "classname" "monster_army" "spawnflags" "768" } { "spawnflags" "768" "targetname" "t101" "classname" "monster_army" "origin" "136 -128 488" "angle" "90" } { "spawnflags" "1792" "origin" "-264 -24 464" "classname" "item_rockets" } { "spawnflags" "2048" "origin" "-240 -8 464" "classname" "item_spikes" } { "classname" "monster_ogre" "origin" "-304 -304 488" "angle" "225" "spawnflags" "769" } { "classname" "func_wall" "spawnflags" "768" "model" "*51" } { "classname" "trap_spikeshooter" "origin" "2048 -48 332" "angle" "270" "spawnflags" "769" "targetname" "t121" } { "origin" "2048 -476 332" "classname" "info_null" "targetname" "t136" } { "style" "32" "origin" "2048 -456 336" "classname" "light" "light" "800" "spawnflags" "1" "target" "t136" "targetname" "t137" } { "style" "32" "classname" "trigger_once" "spawnflags" "768" "target" "t137" "model" "*52" } { "classname" "monster_wizard" "origin" "672 328 384" "angle" "180" "spawnflags" "768" "targetname" "t138" } { "classname" "trigger_once" "target" "t138" "model" "*53" } { "style" "32" "classname" "light" "origin" "2004 -52 332" "light" "100" "spawnflags" "1" "targetname" "t137" } { "classname" "item_shells" "origin" "1416 224 300" "spawnflags" "768" } { "classname" "path_corner" "origin" "-344 136 304" "targetname" "t139" "target" "t140" "spawnflags" "768" } { "origin" "168 128 304" "classname" "path_corner" "target" "t139" "targetname" "t140" "spawnflags" "768" } { "classname" "monster_ogre" "origin" "-400 168 320" "spawnflags" "768" "target" "t139" } { "classname" "trap_spikeshooter" "origin" "2120 -256 332" "angle" "180" "spawnflags" "769" "targetname" "t121" } { "classname" "trap_spikeshooter" "origin" "1944 -456 332" "targetname" "t121" "angle" "90" "spawnflags" "769" } { "classname" "item_spikes" "origin" "-336 -80 470" "spawnflags" "768" } { "targetname" "t143" "classname" "trigger_teleport" "target" "t142" "spawnflags" "2" "model" "*54" } { "targetname" "t143" "classname" "trigger_teleport" "target" "t141" "spawnflags" "2" "model" "*55" } { "classname" "monster_demon1" "origin" "32 840 359" "angle" "270" "targetname" "t143" "spawnflags" "768" } { "angle" "270" "origin" "-192 840 359" "classname" "monster_demon1" "targetname" "t143" "spawnflags" "768" } { "classname" "info_teleport_destination" "origin" "80 216 303" "angle" "270" "targetname" "t141" } { "angle" "270" "origin" "-264 224 303" "classname" "info_teleport_destination" "targetname" "t142" } { "wait" "-1" "target" "t53" "health" "1" "classname" "func_button" "model" "*56" } { "spawnflags" "768" "angle" "270" "origin" "1408 1296 200" "classname" "monster_army" } { "classname" "item_shells" "origin" "772 -856 420" "spawnflags" "768" } { "spawnflags" "1792" "origin" "1248 -1128 420" "classname" "weapon_grenadelauncher" } { "spawnflags" "1793" "origin" "864 -312 440" "classname" "item_rockets" } { "classname" "trigger_once" "message" "Pass through the arch to exit..." "model" "*57" } { "mangle" "20 300 0" "classname" "info_intermission" "origin" "-224 424 512" } { "mangle" "20 45 0" "origin" "1048 -744 488" "classname" "info_intermission" } { "mangle" "20 270 0" "origin" "1104 424 528" "classname" "info_intermission" } { "mangle" "20 45 0" "origin" "1240 984 416" "classname" "info_intermission" } { "sounds" "1" "speed" "20" "classname" "func_button" "angle" "0" "wait" "-1" "target" "t144" "model" "*58" } { "classname" "light" "origin" "400 -1392 480" "light" "150" } { "classname" "func_door" "angle" "-2" "wait" "-1" "speed" "20" "sounds" "1" "targetname" "t144" "model" "*59" } { "classname" "trigger_secret" "model" "*60" } { "classname" "item_artifact_super_damage" "origin" "400 -1360 432" } { "classname" "item_spikes" "origin" "808 -632 192" "spawnflags" "2049" } { "classname" "item_health" "origin" "924 -632 192" "spawnflags" "2048" } { "classname" "weapon_supernailgun" "origin" "880 -616 192" "spawnflags" "1792" } { "classname" "ambient_drip" "origin" "842 978 344" } { "classname" "ambient_drip" "origin" "546 330 400" } { "classname" "info_player_coop" "origin" "1608 1664 264" "angle" "270" } { "angle" "270" "origin" "1392 1664 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "1496 1560 264" "angle" "270" } { "spawnflags" "256" "angle" "270" "origin" "232 -176 320" "classname" "monster_ogre" } { "spawnflags" "1280" "angle" "225" "origin" "-368 -312 480" "classname" "monster_knight" } { "spawnflags" "1792" "classname" "func_wall" "model" "*61" } { "origin" "1810 274 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1802 -102 200" } { "origin" "2050 -214 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "2002 -390 200" } { "origin" "1738 -398 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1346 -398 200" } { "origin" "1138 -542 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "882 -494 200" } { "classname" "ambient_swamp1" "origin" "1722 1090 176" } { "origin" "1242 1090 176" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "1106 642 192" } { "origin" "1346 242 192" "classname" "ambient_swamp2" } { "classname" "ambient_swamp1" "origin" "866 210 192" } { "classname" "ambient_swamp1" "origin" "1802 90 192" } { "origin" "1546 -398 192" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "2042 -310 192" } { "origin" "1178 -398 192" "classname" "ambient_swamp2" } { "classname" "ambient_swamp2" "origin" "1202 -678 192" } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e2m3.ent���������������������������������������������������������0000644�0000000�0000000�00000114075�12425507313�017052� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "classname" "worldspawn" "wad" "gfx/jr_med.wad" "worldtype" "0" "sounds" "9" "message" "the Crypt of Decay" } { "classname" "light" "origin" "192 -648 128" } { "classname" "info_player_start" "origin" "688 -1600 -312" "angle" "180" } { "classname" "light_flame_large_yellow" "origin" "650 -438 4" } { "origin" "386 -438 4" "classname" "light_flame_large_yellow" } { "origin" "66 -886 4" "classname" "light_flame_large_yellow" } { "origin" "322 -886 4" "classname" "light_flame_large_yellow" } { "light" "250" "origin" "192 -1408 288" "classname" "light" } { "light" "250" "classname" "light" "origin" "192 -1088 288" } { "light" "250" "origin" "112 -1248 272" "classname" "light" } { "light" "250" "classname" "light" "origin" "272 -1248 272" } { "light" "200" "origin" "192 -1056 32" "classname" "light" } { "light" "150" "origin" "192 -1248 24" "classname" "light" } { "origin" "194 -1462 108" "classname" "light_flame_large_yellow" } { "origin" "194 -1030 164" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "192 -1440 32" "classname" "light" } { "sounds" "2" "classname" "func_plat" "spawnflags" "1" "model" "*1" } { "origin" "226 -1670 -212" "classname" "light_flame_large_yellow" } { "light" "150" "origin" "88 -1552 -184" "classname" "light" } { "origin" "-22 -1374 -212" "classname" "light_flame_large_yellow" } { "light" "150" "origin" "328 -1256 -184" "classname" "light" } { "light" "150" "classname" "light" "origin" "56 -1256 -184" } { "classname" "light" "origin" "248 -1480 -184" "light" "150" } { "light" "250" "origin" "552 -1608 -72" "classname" "light" } { "light" "150" "origin" "432 -1656 -224" "classname" "light" } { "light" "150" "origin" "432 -1496 -224" "classname" "light" } { "light" "100" "origin" "192 -1248 -40" "classname" "light" } { "origin" "10 -438 4" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-254 -438 4" } { "light" "150" "origin" "192 -704 -136" "classname" "light" } { "light" "250" "origin" "192 -512 -136" "classname" "light" } { "classname" "light" "origin" "416 -512 -136" "light" "150" } { "light" "150" "origin" "-32 -512 -136" "classname" "light" } { "classname" "light" "origin" "-208 -512 -136" "light" "150" } { "light" "150" "origin" "592 -512 -136" "classname" "light" } { "classname" "light" "origin" "192 -840 -136" "light" "150" } { "light" "150" "origin" "-352 -672 -168" "classname" "light" } { "classname" "light" "origin" "-320 -832 -168" "light" "150" } { "light" "150" "origin" "-320 -512 -168" "classname" "light" } { "classname" "light" "origin" "696 -512 -168" "light" "150" } { "light" "150" "origin" "736 -672 -168" "classname" "light" } { "classname" "light" "origin" "704 -832 -168" "light" "150" } { "light" "150" "origin" "512 -864 -168" "classname" "light" } { "classname" "light" "origin" "-128 -864 -168" "light" "150" } { "light" "200" "origin" "-128 -320 8" "classname" "light" } { "classname" "light" "origin" "512 -320 8" "light" "200" } { "origin" "384 -24 32" "classname" "light" } { "classname" "light" "origin" "0 -24 32" } { "light" "200" "origin" "416 -192 -8" "classname" "light" } { "classname" "light" "origin" "-32 -192 -8" "light" "200" } { "light" "200" "origin" "840 48 72" "classname" "light" } { "light" "150" "origin" "576 -24 -56" "classname" "light" } { "light" "200" "origin" "624 -24 72" "classname" "light" } { "origin" "1002 354 -60" "classname" "light_flame_large_yellow" } { "light" "100" "origin" "1000 352 -128" "classname" "light" } { "classname" "light" "origin" "736 8 72" "light" "200" } { "light" "200" "origin" "936 88 72" "classname" "light" } { "light" "150" "origin" "688 -8 -32" "classname" "light" } { "classname" "light" "origin" "784 24 -104" "light" "150" } { "light" "150" "origin" "888 72 -32" "classname" "light" } { "light" "200" "origin" "872 208 -56" "classname" "light" } { "classname" "light" "origin" "872 400 -56" "light" "200" } { "light" "200" "origin" "872 592 -56" "classname" "light" } { "classname" "light" "origin" "744 568 88" "light" "150" } { "light" "150" "origin" "744 648 88" "classname" "light" } { "classname" "light" "origin" "704 608 -80" "light" "150" } { "origin" "866 730 -60" "classname" "light_flame_large_yellow" } { "classname" "light" "origin" "864 728 -128" "light" "100" } { "sounds" "3" "wait" "-1" "targetname" "t8" "spawnflags" "2049" "angle" "0" "classname" "func_door" "model" "*2" } { "spawnflags" "2048" "angle" "90" "target" "t8" "classname" "func_button" "wait" "-1" "model" "*3" } { "origin" "520 608 -64" "classname" "light" } { "light" "400" "origin" "192 608 -24" "classname" "light" } { "sounds" "1" "wait" "-1" "angle" "270" "spawnflags" "2058" "classname" "func_door_secret" "targetname" "t9" "model" "*4" } { "light" "150" "origin" "1064 640 -112" "classname" "light" } { "targetname" "t9" "angle" "180" "origin" "1024 640 -152" "classname" "monster_zombie" } { "targetname" "t9" "angle" "180" "origin" "1120 672 -152" "classname" "monster_zombie" } { "targetname" "t9" "angle" "180" "origin" "1088 600 -152" "classname" "monster_zombie" } { "origin" "976 336 -176" "classname" "item_health" } { "light" "150" "origin" "192 608 -104" "classname" "light" } { "origin" "192 288 -64" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "66 106 4" "light" "200" } { "light" "200" "origin" "-30 106 4" "classname" "light_flame_large_yellow" } { "classname" "light" "origin" "504 120 -248" "light" "200" } { "light" "200" "origin" "704 224 -248" "classname" "light" } { "classname" "light" "origin" "704 472 -248" "light" "200" } { "light" "200" "origin" "304 112 -248" "classname" "light" } { "classname" "light" "origin" "80 112 -248" "light" "200" } { "light" "200" "origin" "720 608 -248" "classname" "light" } { "spawnflags" "2048" "sounds" "1" "wait" "-1" "targetname" "t3" "classname" "func_door" "angle" "90" "model" "*5" } { "spawnflags" "2048" "wait" "-1" "angle" "270" "classname" "func_door" "message" "This door opens nearby..." "model" "*6" } { "spawnflags" "2048" "target" "t3" "wait" "-1" "classname" "func_button" "angle" "180" "model" "*7" } { "light" "250" "origin" "-448 184 0" "classname" "light" } { "light" "150" "origin" "-552 280 -224" "classname" "light" } { "classname" "light" "origin" "-392 280 -224" "light" "150" } { "light" "150" "origin" "-416 -32 104" "classname" "light" } { "classname" "light" "origin" "-320 -32 104" "light" "150" } { "light" "150" "origin" "-224 -32 104" "classname" "light" } { "light" "250" "origin" "-352 -32 -32" "classname" "light" } { "light" "200" "origin" "-1160 88 -248" "classname" "light" } { "light" "200" "origin" "-1048 88 -32" "classname" "light" } { "light" "200" "classname" "light" "origin" "-1160 224 -32" } { "origin" "-742 658 -44" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-926 658 -44" } { "light" "200" "origin" "-736 632 -96" "classname" "light" } { "classname" "light" "origin" "-928 632 -96" "light" "200" } { "light" "150" "origin" "-600 104 -248" "classname" "light" } { "classname" "light" "origin" "-696 424 -248" "light" "150" } { "light" "150" "origin" "-1152 408 -248" "classname" "light" } { "classname" "light" "origin" "-944 432 -248" "light" "150" } { "light" "150" "origin" "-856 64 -248" "classname" "light" } { "classname" "light" "origin" "-160 152 -248" "light" "150" } { "light" "150" "origin" "-160 448 -248" "classname" "light" } { "classname" "light" "origin" "-328 464 -248" "light" "150" } { "light" "150" "origin" "-256 176 -248" "classname" "light" } { "origin" "-574 410 -172" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-470 410 -172" } { "target" "t4" "classname" "trigger_teleport" "model" "*8" } { "light" "200" "style" "2" "origin" "-760 576 -216" "classname" "light" } { "targetname" "t4" "angle" "180" "origin" "120 -32 -112" "classname" "info_teleport_destination" } { "light" "200" "origin" "-264 384 112" "classname" "light" } { "classname" "light" "origin" "-264 288 112" "light" "200" } { "light" "200" "origin" "-264 192 112" "classname" "light" } { "classname" "light" "origin" "-264 480 112" "light" "200" } { "light" "250" "origin" "-264 304 -56" "classname" "light" } { "classname" "light" "origin" "-520 424 0" "light" "250" } { "light" "200" "origin" "-1120 608 72" "classname" "light" } { "classname" "light" "origin" "-1024 584 72" "light" "200" } { "light" "200" "origin" "-928 584 72" "classname" "light" } { "classname" "light" "origin" "-832 584 72" "light" "200" } { "light" "200" "origin" "-544 584 72" "classname" "light" } { "classname" "light" "origin" "-640 584 72" "light" "200" } { "light" "150" "origin" "-480 768 56" "classname" "light" } { "classname" "light" "origin" "-384 768 56" "light" "150" } { "classname" "light" "origin" "-712 120 -32" "light" "200" } { "sounds" "3" "wait" "-1" "targetname" "t5" "spawnflags" "2049" "angle" "180" "classname" "func_door" "model" "*9" } { "spawnflags" "2048" "angle" "270" "target" "t5" "wait" "-1" "classname" "func_button" "model" "*10" } { "style" "32" "targetname" "t5" "light" "200" "origin" "-352 552 -56" "classname" "light" } { "light" "150" "origin" "-432 768 -56" "classname" "light" } { "light" "150" "origin" "-520 680 -56" "classname" "light" } { "spawnflags" "2048" "sounds" "3" "targetname" "t5" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*11" } { "sounds" "3" "targetname" "t5" "spawnflags" "2049" "wait" "-1" "angle" "90" "classname" "func_door" "model" "*12" } { "origin" "-72 848 -56" "classname" "light" } { "origin" "-120 600 -8" "classname" "light" } { "classname" "light" "origin" "192 904 -8" } { "light" "200" "origin" "192 888 -248" "classname" "light" } { "classname" "light" "origin" "-104 600 -248" "light" "200" } { "light" "200" "origin" "376 984 -120" "classname" "light" } { "classname" "light" "origin" "504 760 -120" "light" "200" } { "light" "200" "origin" "-32 608 200" "classname" "light" } { "spawnflags" "2048" "sounds" "3" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*13" } { "origin" "-16 1456 16" "classname" "light" } { "light" "200" "origin" "384 1248 -56" "classname" "light" } { "classname" "light" "origin" "384 1440 -56" "light" "200" } { "light" "150" "origin" "256 1440 -56" "classname" "light" } { "classname" "light" "origin" "192 1248 -56" "light" "200" } { "light" "200" "origin" "384 1344 -88" "classname" "light" } { "classname" "light" "origin" "192 1152 -88" "light" "200" } { "classname" "light" "origin" "8 1456 -120" "light" "200" } { "spawnflags" "2048" "sounds" "1" "classname" "item_key2" "origin" "-16 1456 -152" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "model" "*14" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "model" "*15" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "spawnflags" "2048" "model" "*16" } { "classname" "trigger_once" "target" "t6" "model" "*17" } { "classname" "light" "origin" "-192 1456 -136" "light" "80" } { "classname" "light" "origin" "-16 1280 -136" "light" "80" } { "spawnflags" "768" "classname" "monster_hell_knight" "origin" "-16 1280 -168" "angle" "90" "targetname" "t6" } { "spawnflags" "256" "angle" "270" "origin" "-16 1632 -168" "classname" "monster_hell_knight" "targetname" "t6" } { "classname" "monster_hell_knight" "origin" "-192 1456 -168" "angle" "0" "targetname" "t6" } { "classname" "light" "origin" "152 1440 -56" "light" "150" } { "classname" "item_shells" "origin" "-104 1512 -192" "spawnflags" "1" } { "wait" "-1" "classname" "func_door" "angle" "0" "spawnflags" "2056" "model" "*18" } { "wait" "-1" "classname" "func_door" "angle" "180" "spawnflags" "2056" "model" "*19" } { "classname" "light" "origin" "-1120 832 -48" "light" "250" } { "classname" "light" "origin" "-1120 976 -24" "light" "250" } { "classname" "light" "origin" "-1240 1296 216" "light" "200" } { "light" "200" "origin" "-1240 1416 216" "classname" "light" } { "classname" "light" "origin" "-1240 1176 216" "light" "200" } { "classname" "light" "origin" "-712 1416 216" "light" "200" } { "light" "200" "origin" "-712 1296 216" "classname" "light" } { "classname" "light" "origin" "-712 1176 216" "light" "200" } { "light" "200" "origin" "-856 1296 216" "classname" "light" } { "classname" "light" "origin" "-1096 1296 216" "light" "200" } { "light" "200" "origin" "-976 1296 216" "classname" "light" } { "classname" "light_flame_small_white" "origin" "-1318 1514 -8" } { "origin" "-1318 1514 64" "classname" "light_flame_small_white" } { "classname" "light_flame_small_white" "origin" "-1318 1514 144" } { "origin" "-634 1078 -8" "classname" "light_flame_small_white" } { "classname" "light_flame_small_white" "origin" "-634 1078 64" } { "origin" "-634 1078 144" "classname" "light_flame_small_white" } { "classname" "func_plat" "spawnflags" "1" "model" "*20" } { "classname" "light" "origin" "-320 1536 184" "light" "250" } { "classname" "light" "origin" "-376 1312 120" "light" "250" } { "classname" "light" "origin" "-16 1536 184" "light" "200" } { "light" "200" "origin" "-560 1312 56" "classname" "light" } { "classname" "light" "origin" "24 1120 216" "light" "150" } { "classname" "light" "origin" "192 608 176" "light" "200" } { "wait" "-1" "classname" "func_door" "angle" "90" "spawnflags" "2049" "targetname" "t7" "sounds" "1" "model" "*21" } { "light" "150" "origin" "400 1104 224" "classname" "light" } { "light" "150" "origin" "-200 1056 224" "classname" "light" } { "light" "200" "origin" "192 960 224" "classname" "light" } { "light" "200" "origin" "192 784 224" "classname" "light" } { "classname" "light" "origin" "672 264 184" "light" "200" } { "light" "200" "origin" "384 184 184" "classname" "light" } { "classname" "light" "origin" "512 256 8" "light" "200" } { "classname" "light" "origin" "8 184 200" "light" "200" } { "classname" "light" "origin" "584 744 200" "light" "200" } { "classname" "light" "origin" "0 432 200" "light" "200" } { "classname" "trigger_once" "targetname" "t8" "target" "t9" "delay" "10" "model" "*22" } { "classname" "light" "origin" "192 -72 216" "light" "250" } { "classname" "light" "origin" "360 -168 360" "light" "200" } { "classname" "light" "origin" "296 -168 360" "light" "200" } { "origin" "472 -168 368" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "408 -168 360" } { "classname" "light" "origin" "384 -168 248" "light" "200" } { "classname" "light" "origin" "936 -304 328" "light" "200" } { "light" "200" "origin" "1000 -232 360" "classname" "light" } { "classname" "light" "origin" "864 -232 360" "light" "200" } { "light" "200" "origin" "864 -368 360" "classname" "light" } { "classname" "light" "origin" "1000 -368 360" "light" "200" } { "classname" "light" "origin" "736 -248 280" "light" "200" } { "light" "200" "origin" "552 -216 280" "classname" "light" } { "classname" "light" "origin" "16 144 -32" "light" "200" } { "classname" "light" "origin" "0 432 -136" "light" "200" } { "classname" "light" "origin" "192 384 184" "light" "200" } { "light" "200" "origin" "192 192 184" "classname" "light" } { "spawnflags" "2048" "classname" "func_button" "wait" "-1" "target" "t7" "model" "*23" } { "style" "33" "targetname" "t7" "classname" "light" "origin" "176 1152 200" "target" "t10" } { "classname" "info_null" "origin" "292 1152 180" "targetname" "t10" } { "classname" "light" "origin" "192 1224 200" "light" "150" } { "light" "150" "origin" "192 1376 200" "classname" "light" } { "classname" "light" "origin" "192 1536 200" "light" "200" } { "light" "150" "origin" "192 1080 200" "classname" "light" } { "classname" "weapon_nailgun" "origin" "184 -1520 -272" } { "classname" "func_button" "target" "t11" "angle" "-1" "targetname" "t12" "lip" "4" "wait" "0.1" "speed" "300" "health" "1" "model" "*24" } { "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t11" "wait" "10" "model" "*25" "lip" "7" // svdijk -- added to prevent z-fighting } { "classname" "func_door_secret" "angle" "90" "spawnflags" "8" "targetname" "t11" "model" "*26" "t_length" "65" // svdijk -- added to prevent z-fighting } { "classname" "light" "origin" "1248 -288 312" "light" "150" } { "light" "200" "origin" "1176 -400 352" "classname" "light" } { "classname" "item_health" "origin" "1336 -536 256" "spawnflags" "2" } { "classname" "light" "origin" "1320 -488 352" "light" "200" } { "classname" "trigger_multiple" "target" "t11" "wait" "10" "model" "*27" } { "classname" "item_armor1" "origin" "192 -592 -64" } { "classname" "item_shells" "origin" "176 592 -160" "spawnflags" "1" } { "classname" "weapon_nailgun" "origin" "-80 1456 -192" "spawnflags" "1792" } { "classname" "weapon_rocketlauncher" "origin" "56 1144 128" "spawnflags" "1792" } { "classname" "weapon_grenadelauncher" "origin" "-736 608 -280" "spawnflags" "1792" } { "classname" "item_spikes" "origin" "1120 -384 256" "spawnflags" "1" } { "classname" "item_rockets" "origin" "840 -432 192" "spawnflags" "1" } { "classname" "item_spikes" "origin" "-456 312 -80" } { "classname" "monster_zombie" "origin" "-1152 96 -88" "spawnflags" "256" "target" "t36" } { "origin" "-1120 32 -88" "classname" "monster_zombie" "spawnflags" "768" "target" "t36" } { "classname" "monster_zombie" "origin" "-1192 168 -88" "target" "t36" } { "classname" "monster_shambler" "origin" "-1120 1104 -56" "angle" "270" } { "classname" "monster_hell_knight" "origin" "-336 1312 8" "angle" "180" } { "classname" "monster_ogre" "origin" "-698 1446 -56" "angle" "270" "spawnflags" "256" } { "classname" "monster_hell_knight" "origin" "-888 1128 8" "angle" "90" "spawnflags" "256" } { "classname" "item_health" "origin" "-336 784 -128" } { "origin" "-408 608 -128" "classname" "item_health" } { "classname" "path_corner" "origin" "-1096 584 -120" "targetname" "t13" "target" "t14" } { "origin" "-496 584 -120" "classname" "path_corner" "targetname" "t14" "target" "t13" } { "classname" "monster_demon1" "origin" "-712 576 -104" "angle" "180" "target" "t13" } { "classname" "path_corner" "origin" "-528 472 -96" "targetname" "t15" "target" "t16" } { "origin" "-368 -32 -96" "classname" "path_corner" "target" "t15" "targetname" "t16" } { "classname" "monster_ogre" "origin" "-466 262 -56" "target" "t16" "spawnflags" "256" } { "target" "t22" "targetname" "t21" "origin" "56 -184 -120" "classname" "path_corner" } { "target" "t21" "targetname" "t20" "classname" "path_corner" "origin" "-128 -224 -120" } { "target" "t20" "targetname" "t19" "origin" "-128 -504 -56" "classname" "path_corner" } { "target" "t19" "targetname" "t18" "classname" "path_corner" "origin" "512 -504 -56" } { "target" "t18" "targetname" "t17" "origin" "512 -224 -120" "classname" "path_corner" } { "targetname" "t26" "target" "t17" "classname" "path_corner" "origin" "328 -184 -120" } { "target" "t23" "targetname" "t22" "classname" "path_corner" "origin" "-128 -200 -120" } { "target" "t24" "targetname" "t23" "classname" "path_corner" "origin" "-128 -552 -56" } { "target" "t25" "targetname" "t24" "origin" "512 -552 -56" "classname" "path_corner" } { "target" "t26" "targetname" "t25" "classname" "path_corner" "origin" "512 -200 -120" } { "spawnflags" "256" "target" "t21" "origin" "0 -184 -104" "classname" "monster_hell_knight" } { "spawnflags" "1" "origin" "376 -160 -104" "classname" "monster_hell_knight" } { "spawnflags" "768" "angle" "270" "origin" "190 -706 -40" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "90" "origin" "192 -1408 24" "classname" "monster_hell_knight" } { "origin" "40 -1424 0" "classname" "item_shells" "spawnflags" "1" } { "spawnflags" "1" "origin" "304 -1096 0" "classname" "item_health" } { "origin" "328 -1280 -272" "classname" "item_health" } { "origin" "40 -1256 -272" "classname" "item_spikes" } { "target" "t28" "targetname" "t27" "origin" "864 176 -168" "classname" "path_corner" } { "target" "t27" "targetname" "t28" "classname" "path_corner" "origin" "864 616 -168" } { "target" "t27" "origin" "862 446 -152" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "180" "origin" "526 -26 -104" "classname" "monster_ogre" } { "spawnflags" "256" "angle" "0" "origin" "-72 -24 -104" "classname" "monster_hell_knight" } { "spawnflags" "256" "origin" "-274 -34 -104" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "270" "origin" "-512 760 -104" "classname" "monster_hell_knight" } { "spawnflags" "1793" "origin" "336 1104 128" "classname" "item_rockets" } { "angle" "45" "spawnflags" "256" "origin" "104 256 -136" "classname" "monster_zombie" } { "spawnflags" "769" "angle" "90" "origin" "192 488 -136" "classname" "monster_hell_knight" } { "wait" "1" "speed" "250" "lip" "16" "spawnflags" "5" "targetname" "t29" "dmg" "20" "angle" "180" "classname" "func_door" "model" "*28" } { "wait" "1" "targetname" "t29" "speed" "250" "dmg" "20" "lip" "16" "spawnflags" "5" "classname" "func_door" "sounds" "1" "model" "*29" } { "wait" "2" "target" "t29" "classname" "trigger_multiple" "model" "*30" } { "origin" "506 1762 -124" "classname" "light_torch_small_walltorch" "style" "1" } { "classname" "light_torch_small_walltorch" "origin" "274 2010 -124" } { "light" "200" "origin" "152 1824 -40" "classname" "light" } { "classname" "light" "origin" "288 1824 -40" "light" "200" } { "light" "200" "origin" "288 1696 -40" "classname" "light" } { "classname" "light" "origin" "152 1704 -40" "light" "200" } { "light" "220" "origin" "0 1704 -40" "classname" "light" } { "angle" "180" "classname" "func_door_secret" "targetname" "t35" "spawnflags" "16" "sounds" "1" "model" "*31" } { "spawnflags" "2" "origin" "-16 1816 -192" "classname" "item_health" } { "origin" "432 1672 -320" "classname" "light" "light" "220" } { "spawnflags" "1792" "origin" "-16 1752 -192" "classname" "item_rockets" } { "angle" "270" "origin" "-192 1580 168" "classname" "trap_spikeshooter" "targetname" "t32" } { "spawnflags" "256" "classname" "trap_spikeshooter" "origin" "236 1536 168" "angle" "180" "targetname" "t32" } { "classname" "trap_spikeshooter" "origin" "0 1580 168" "angle" "270" "targetname" "t32" } { "angle" "90" "origin" "-96 1492 168" "classname" "trap_spikeshooter" "targetname" "t32" } { "classname" "trap_spikeshooter" "origin" "148 1376 168" "angle" "0" "targetname" "t33" } { "angle" "180" "origin" "236 1256 168" "classname" "trap_spikeshooter" "targetname" "t33" } { "spawnflags" "256" "classname" "trap_spikeshooter" "origin" "192 1580 168" "angle" "270" "targetname" "t33" } { "spawnflags" "257" "angle" "90" "origin" "192 -16 153" "classname" "monster_hell_knight" } { "spawnflags" "257" "angle" "180" "origin" "864 -248 217" "classname" "monster_shambler" } { "angle" "180" "origin" "464 -184 185" "classname" "monster_hell_knight" } { "classname" "monster_hell_knight" "origin" "192 -176 153" "angle" "90" "spawnflags" "1" "target" "t31" } { "spawnflags" "769" "angle" "90" "origin" "190 1166 153" "classname" "monster_ogre" } { "spawnflags" "2048" "origin" "48 1456 -192" "classname" "weapon_grenadelauncher" } { "spawnflags" "1" "origin" "-96 1376 -192" "classname" "item_rockets" } { "angle" "270" "spawnflags" "768" "classname" "monster_ogre" "origin" "862 662 -152" } { "light" "120" "origin" "192 -352 -264" "classname" "light" } { "spawnflags" "768" "origin" "326 -1490 -248" "classname" "monster_ogre" "angle" "180" "target" "t42" } { "origin" "192 552 128" "classname" "item_health" } { "spawnflags" "1024" "classname" "item_health" "origin" "176 672 128" } { "spawnflags" "1025" "origin" "184 1312 128" "classname" "item_health" } { "classname" "item_health" "origin" "-16 1480 128" "spawnflags" "1025" } { "origin" "672 -328 176" "classname" "item_health" } { "classname" "item_health" "origin" "776 -192 176" } { "origin" "784 312 -176" "classname" "item_shells" } { "spawnflags" "256" "angle" "315" "origin" "-26 1094 152" "classname" "monster_ogre" } { "classname" "monster_ogre" "origin" "406 1094 152" "angle" "225" "spawnflags" "768" } { "spawnflags" "1" "origin" "-200 1128 128" "classname" "item_rockets" } { "origin" "-550 -478 212" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "-550 -166 212" } { "origin" "-214 -326 252" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "-120 -176 192" "classname" "light" } { "classname" "light" "origin" "56 -176 192" "light" "150" } { "origin" "-816 1488 -80" "classname" "item_health" } { "classname" "item_health" "origin" "-752 1488 -80" } { "spawnflags" "1536" "origin" "-688 1488 -80" "classname" "item_health" } { "spawnflags" "1" "origin" "176 1264 -160" "classname" "item_shells" } { "classname" "func_door" "angle" "270" "targetname" "t31" "wait" "-1" "spawnflags" "2048" "model" "*32" } { "wait" "-1" "sounds" "1" "speed" "300" "classname" "func_door" "angle" "90" "model" "*33" } { "speed" "300" "classname" "func_door" "angle" "270" "wait" "-1" "model" "*34" } { "classname" "item_health" "origin" "400 1464 -160" "spawnflags" "1024" } { "classname" "item_health" "origin" "-1136 528 -128" } { "classname" "monster_ogre" "origin" "-370 -218 88" "targetname" "t31" "spawnflags" "1" } { "classname" "monster_hell_knight" "origin" "-64 -176 152" "angle" "0" "spawnflags" "768" "targetname" "t31" } { "classname" "item_health" "origin" "-488 -480 64" } { "classname" "light" "origin" "680 -1600 -160" } { "classname" "item_spikes" "origin" "984 -192 192" "spawnflags" "1" } { "classname" "monster_ogre" "origin" "-490 -410 88" "angle" "45" } { "classname" "trigger_multiple" "target" "t32" "wait" "1" "spawnflags" "1024" "targetname" "t44" "model" "*35" } { "classname" "trigger_multiple" "target" "t33" "wait" "1" "spawnflags" "1024" "model" "*36" } { "classname" "item_rockets" "origin" "-96 272 -384" } { "classname" "weapon_supernailgun" "origin" "-1200 208 -112" "spawnflags" "1792" } { "classname" "func_door_secret" "spawnflags" "2051" "targetname" "t36" "angle" "90" "model" "*37" "t_length" "65" // svdijk -- added to prevent z-fighting } { "classname" "light" "origin" "-1288 640 -80" "light" "160" } { "light" "160" "origin" "-1288 128 -80" "classname" "light" } { "classname" "light" "origin" "-1288 264 -80" "light" "160" } { "light" "160" "origin" "-1288 392 -80" "classname" "light" } { "classname" "light" "origin" "-1288 520 -80" "light" "160" } { "classname" "func_door_secret" "targetname" "t36" "angle" "270" "spawnflags" "2049" "model" "*38" "t_length" "65" // svdijk -- added to prevent z-fighting } { "classname" "item_armor2" "origin" "1128 600 -176" "spawnflags" "1024" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "11" "targetname" "t34" "model" "*39" } { "classname" "light_torch_small_walltorch" "origin" "-246 -1310 -204" "light" "250" } { "classname" "trigger_once" "target" "t34" "model" "*40" } { "classname" "item_spikes" "origin" "-240 -1288 -312" "spawnflags" "1" } { "spawnflags" "1" "origin" "-240 -1368 -312" "classname" "item_spikes" } { "sounds" "3" "classname" "func_door" "angle" "-2" "spawnflags" "3585" "wait" "90" "targetname" "t6" "model" "*41" } { "sounds" "3" "classname" "func_door" "targetname" "t6" "spawnflags" "3585" "angle" "-2" "wait" "90" "model" "*42" } { "sounds" "3" "classname" "func_door" "angle" "0" "spawnflags" "1537" "targetname" "t6" "wait" "90" "model" "*43" } { "classname" "light_torch_small_walltorch" "origin" "-42 1642 -108" "light" "200" } { "classname" "item_health" "origin" "-72 560 -384" } { "origin" "-152 560 -384" "classname" "item_health" } { "targetname" "t31" "spawnflags" "513" "angle" "90" "origin" "848 -376 216" "classname" "monster_hell_knight" } { "targetname" "t31" "spawnflags" "768" "origin" "-512 -248 88" "classname" "monster_shambler" } { "spawnflags" "768" "angle" "180" "origin" "382 1246 -136" "classname" "monster_ogre" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "190 1438 -136" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "640 -1664 -312" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "-400 -240 88" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "-216 1088 152" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "-512 792 -104" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "888 624 -152" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "-96 1456 -168" "angle" "0" } { "spawnflags" "2048" "classname" "func_wall" "model" "*44" } { "spawnflags" "2048" "classname" "func_wall" "model" "*45" } { "classname" "func_plat" "height" "192" "sounds" "2" "model" "*46" } { "classname" "item_health" "origin" "-1184 72 -352" } { "classname" "light" "origin" "-952 1408 80" "light" "200" } { "classname" "light" "origin" "-1120 1176 48" "light" "250" } { "classname" "light" "origin" "-104 288 -344" "light" "200" } { "classname" "light" "origin" "-512 376 -304" "light" "200" } { "classname" "trigger_multiple" "target" "t35" "model" "*47" } { "classname" "light" "origin" "192 -376 -16" "light" "150" } { "classname" "light" "origin" "192 -328 176" "light" "150" } { "classname" "trigger_multiple" "target" "t32" "spawnflags" "768" "wait" "0.5" "model" "*48" } { "classname" "trigger_multiple" "spawnflags" "768" "wait" "0.5" "target" "t33" "targetname" "t44" "model" "*49" } { "origin" "-1176 112 -112" "classname" "item_rockets" } { "origin" "-736 544 -280" "classname" "item_armorInv" } { "classname" "func_button" "angle" "180" "target" "t36" "model" "*50" } { "classname" "info_null" "origin" "-1332 1116 -36" "targetname" "t37" } { "classname" "light" "origin" "-1296 1120 -32" "target" "t37" "angle" "60" } { "spawnflags" "2048" "classname" "func_wall" "model" "*51" } { "spawnflags" "2048" "classname" "func_wall" "model" "*52" } { "classname" "light" "origin" "192 -152 -344" "light" "160" } { "classname" "light" "origin" "192 32 -344" "light" "160" } { "classname" "light" "origin" "32 168 -344" "light" "140" } { "light" "160" "origin" "-16 408 -344" "classname" "light" } { "classname" "light" "origin" "192 368 -344" "light" "140" } { "light" "140" "origin" "448 368 -344" "classname" "light" } { "classname" "light" "origin" "528 592 -344" "light" "200" } { "light" "200" "origin" "408 808 -344" "classname" "light" } { "classname" "light" "origin" "192 832 -344" "light" "200" } { "light" "200" "origin" "-40 728 -344" "classname" "light" } { "classname" "light" "origin" "-168 632 -344" "light" "200" } { "light" "200" "origin" "-160 976 -344" "classname" "light" } { "classname" "light" "origin" "592 456 -344" "light" "200" } { "classname" "light" "origin" "192 352 -232" "light" "200" } { "light" "200" "origin" "32 264 -232" "classname" "light" } { "classname" "light" "origin" "-184 432 -336" "light" "160" } { "light" "160" "origin" "-192 144 -336" "classname" "light" } { "classname" "light" "origin" "-776 280 -312" "light" "200" } { "light" "200" "origin" "-864 432 -312" "classname" "light" } { "classname" "light" "origin" "-1096 432 -312" "light" "200" } { "light" "200" "origin" "-1168 272 -312" "classname" "light" } { "classname" "light" "origin" "-944 64 -312" "light" "200" } { "light" "200" "origin" "-664 136 -312" "classname" "light" } { "light" "200" "origin" "-1112 592 -96" "classname" "light" } { "classname" "light" "origin" "-1040 1256 -32" "light" "150" } { "light" "200" "origin" "-880 1128 80" "classname" "light" } { "classname" "light" "origin" "-712 1400 -16" "light" "200" } { "classname" "light" "origin" "104 -600 -224" "light" "200" } { "light" "200" "origin" "280 -600 -224" "classname" "light" } { "classname" "trigger_changelevel" "map" "e2m4" "model" "*53" } { "light" "160" "origin" "-312 808 -72" "classname" "light" } { "light" "200" "origin" "192 1776 -312" "classname" "light" } { "classname" "light" "origin" "-392 568 -56" "light" "160" } { "classname" "light" "origin" "-1224 1504 8" "light" "170" } { "light" "170" "origin" "-1304 1392 8" "classname" "light" } { "classname" "light" "origin" "-640 1168 -8" "light" "170" } { "light" "160" "origin" "352 -1248 56" "classname" "light" } { "classname" "light" "origin" "40 -1248 56" "light" "160" } { "light" "160" "origin" "192 -1216 -176" "classname" "light" } { "classname" "light" "origin" "24 -1376 -232" "light" "160" } { "light" "160" "origin" "224 -1624 -232" "classname" "light" } { "classname" "light" "origin" "368 -1392 -232" "light" "160" } { "classname" "light" "origin" "8 -464 -40" "light" "140" } { "light" "140" "origin" "384 -464 -40" "classname" "light" } { "classname" "light" "origin" "-544 800 -56" "light" "140" } { "classname" "trigger_secret" "model" "*54" } { "classname" "trigger_secret" "model" "*55" } { "light" "200" "origin" "760 1856 -40" "classname" "light" } { "classname" "light" "origin" "760 1664 -40" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "538 1762 -124" "style" "1" "light" "200" } { "style" "1" "classname" "light_torch_small_walltorch" "origin" "850 1930 -124" "light" "200" } { "origin" "850 1618 -124" "classname" "light_torch_small_walltorch" "style" "1" "light" "200" } { "classname" "light" "origin" "912 1856 -40" "light" "200" } { "light" "200" "origin" "912 1664 -40" "classname" "light" } { "light" "200" "origin" "1064 1776 -172" "classname" "light" } { "light" "200" "origin" "1080 1856 -40" "classname" "light" } { "classname" "light" "origin" "1080 1664 -40" "light" "200" } { "classname" "light" "origin" "1176 1776 -172" "light" "200" } { "light" "170" "origin" "672 1768 -296" "classname" "light" } { "target" "t38" "classname" "trigger_teleport" "model" "*56" } { "targetname" "t38" "origin" "1144 1776 -88" "classname" "info_teleport_destination" } { "map" "e2m7" "classname" "trigger_changelevel" "model" "*57" } { "light" "160" "origin" "840 1768 -200" "classname" "light" } { "light" "140" "origin" "408 608 -344" "classname" "light" } { "classname" "item_spikes" "origin" "-16 240 -160" "spawnflags" "2048" } { "classname" "weapon_supernailgun" "origin" "-1256 1448 -80" } { "origin" "432 1160 152" "classname" "item_artifact_super_damage" } { "message" "The portal lies beyond..." "targetname" "t40" "wait" "-1" "speed" "20" "sounds" "4" "angle" "-2" "classname" "func_door" "model" "*58" } { "origin" "432 1672 -368" "classname" "item_armor2" } { "target" "t39" "sounds" "1" "wait" "-1" "classname" "func_button" "model" "*59" } { "message" "The underwater barrier is lowered..." "target" "t40" "targetname" "t39" "spawnflags" "1" "classname" "trigger_once" "model" "*60" } { "classname" "trigger_secret" "model" "*61" } { "light" "200" "origin" "-128 -704 -224" "classname" "light" } { "classname" "light" "origin" "512 -704 -224" "light" "200" } { "light" "200" "origin" "192 -832 -224" "classname" "light" } { "mangle" "20 240 0" "origin" "400 1048 240" "classname" "info_intermission" } { "mangle" "20 145 0" "origin" "-160 144 64" "classname" "info_intermission" } { "mangle" "-20 45 0" "origin" "-320 -824 -144" "classname" "info_intermission" } { "classname" "func_wall" "spawnflags" "1792" "model" "*62" } { "classname" "item_artifact_super_damage" "origin" "928 1768 -240" "spawnflags" "1792" } { "classname" "light" "origin" "8 1800 -120" "light" "220" } { "classname" "weapon_lightning" "origin" "1216 1784 -264" "spawnflags" "1792" } { "classname" "item_cells" "origin" "880 1648 -264" "spawnflags" "1793" } { "spawnflags" "1793" "origin" "880 1864 -264" "classname" "item_cells" } { "spawnflags" "1792" "classname" "func_wall" "model" "*63" } { "spawnflags" "1792" "classname" "func_wall" "model" "*64" } { "spawnflags" "1792" "classname" "func_wall" "model" "*65" } { "classname" "info_player_coop" "origin" "664 -1520 -312" "angle" "180" } { "angle" "180" "origin" "592 -1600 -312" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "680 -1712 -312" "angle" "180" } { "classname" "air_bubbles" "origin" "720 1384 -320" } { "classname" "light" "origin" "680 1376 -312" } { "classname" "func_door_secret" "angle" "180" "spawnflags" "2" "targetname" "t41" "model" "*66" "t_length" "65" // svdijk -- added to prevent z-fighting } { "classname" "trigger_multiple" "target" "t41" "model" "*67" } { "origin" "688 1176 -312" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "480 1408 -312" } { "origin" "448 1552 -312" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "840 1080 -312" } { "origin" "840 1080 -160" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "840 1080 0" } { "classname" "light" "origin" "840 1080 232" "light" "200" } { "classname" "item_artifact_envirosuit" "origin" "576 1440 -344" } { "classname" "item_artifact_invulnerability" "origin" "544 1248 -344" } { "light" "200" "origin" "840 936 232" "classname" "light" } { "classname" "light" "origin" "840 760 232" "light" "150" } { "light" "120" "origin" "808 600 232" "classname" "light" } { "classname" "item_health" "origin" "824 960 152" } { "origin" "848 880 152" "classname" "item_health" } { "classname" "item_health" "origin" "808 768 152" } { "classname" "trigger_multiple" "message" "Welcome to the Well of Wishes!" "wait" "5" "sounds" "1" "model" "*68" } { "classname" "trigger_multiple" "sounds" "1" "wait" "3" "message" "The Dopefish Lives!" "model" "*69" } { "classname" "func_wall" "spawnflags" "1792" "model" "*70" } { "classname" "trigger_secret" "model" "*71" } { "spawnflags" "1" "origin" "-1312 1392 -80" "classname" "item_spikes" } { "classname" "func_wall" "spawnflags" "1792" "model" "*72" } { "classname" "light" "origin" "-544 600 -248" "light" "200" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "194 -214 196" "spawnflags" "2048" } { "light" "200" "origin" "352 984 -328" "classname" "light" } { "classname" "light" "origin" "96 976 -328" "light" "200" } { "classname" "light" "origin" "640 776 -336" "light" "200" } { "classname" "func_plat" "spawnflags" "1" "model" "*73" } { "classname" "monster_fish" "origin" "656 352 -336" "spawnflags" "256" } { "spawnflags" "256" "origin" "432 424 -336" "classname" "monster_fish" } { "classname" "monster_fish" "origin" "296 968 -336" "spawnflags" "256" } { "origin" "-48 800 -336" "classname" "monster_fish" } { "classname" "monster_fish" "origin" "-896 248 -312" } { "origin" "-744 328 -312" "classname" "monster_fish" } { "classname" "path_corner" "origin" "272 -1504 -264" "targetname" "t42" "target" "t43" } { "origin" "56 -1352 -264" "classname" "path_corner" "target" "t42" "targetname" "t43" } { "classname" "item_health" "origin" "312 -1336 -272" } { "origin" "544 -1488 -336" "classname" "item_health" } { "classname" "item_health" "origin" "312 1464 -160" } { "origin" "56 1488 -192" "classname" "item_health" } { "classname" "trigger_once" "killtarget" "t44" "spawnflags" "3072" "model" "*74" } { "classname" "item_rockets" "origin" "216 648 120" "spawnflags" "1" } { "classname" "item_shells" "origin" "136 648 120" "spawnflags" "1" } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e1m1.ent.orig����������������������������������������������������0000644�0000000�0000000�00000063253�12403131422�017775� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "worldtype" "2" "sounds" "6" "classname" "worldspawn" "wad" "gfx/base.wad" "message" "the Slipgate Complex" } { "classname" "info_player_start" "origin" "480 -352 88" "angle" "90" } { "classname" "light" "origin" "480 96 168" "light" "250" } { "classname" "light" "origin" "480 288 168" "light" "250" } { "classname" "light" "origin" "272 96 80" } { "origin" "272 288 80" "classname" "light" } { "classname" "light" "origin" "272 192 80" } { "origin" "688 192 80" "classname" "light_fluorospark" "style" "10" } { "style" "10" "classname" "light" "origin" "688 288 80" } { "origin" "688 96 80" "classname" "light" "style" "10" } { "classname" "light" "origin" "480 -280 168" "light" "200" } { "origin" "480 -144 168" "classname" "light" "light" "200" } { "classname" "light" "origin" "480 -376 120" "light" "200" } { "light" "160" "origin" "480 -40 168" "classname" "light" } { "speed" "400" "sounds" "2" "angle" "270" "classname" "func_door" "model" "*1" } { "speed" "400" "angle" "90" "classname" "func_door" "model" "*2" } { "light" "250" "origin" "592 544 88" "classname" "light_fluoro" } { "origin" "456 600 104" "classname" "light" } { "light" "180" "origin" "688 648 136" "classname" "light" } { "classname" "light" "origin" "688 520 136" "light" "180" } { "origin" "688 480 80" "classname" "item_armor1" } { "angle" "180" "spawnflags" "768" "origin" "616 72 40" "classname" "monster_army" } { "light" "250" "origin" "0 576 120" "classname" "light" } { "light" "180" "origin" "160 576 72" "classname" "light" } { "light" "200" "origin" "560 -32 72" "classname" "light" } { "light" "200" "classname" "light" "origin" "400 -32 72" } { "light" "200" "origin" "0 712 72" "classname" "light" } { "classname" "light" "origin" "0 728 -136" "light" "200" } { "light" "200" "origin" "0 592 -136" "classname" "light" } { "wait" "5" "angle" "-2" "sounds" "2" "targetname" "t1" "classname" "func_door" "dmg" "10" "model" "*3" } { "sounds" "1" "target" "t1" "angle" "180" "classname" "func_button" "model" "*4" } { "light" "200" "origin" "412 780 136" "classname" "light" } { "light" "200" "classname" "light" "origin" "328 904 72" } { "light" "200" "origin" "168 800 72" "classname" "light" } { "light" "200" "classname" "light" "origin" "-72 864 72" } { "origin" "264 888 -136" "classname" "light" } { "classname" "light" "origin" "-8 992 -136" "light" "200" } { "light" "250" "classname" "light" "origin" "272 1064 -136" } { "light" "250" "origin" "-8 1232 -136" "classname" "light" } { "light" "250" "classname" "light" "origin" "256 1272 -136" } { "light" "250" "origin" "312 1464 -136" "classname" "light" } { "light" "200" "origin" "128 968 72" "classname" "light" } { "light" "250" "classname" "light" "origin" "-48 1168 72" } { "light" "250" "origin" "312 1168 72" "classname" "light" } { "light" "220" "classname" "light" "origin" "128 1504 -120" } { "light" "250" "classname" "light" "origin" "-56 1464 -136" } { "sounds" "2" "classname" "func_door" "angle" "180" "speed" "400" "model" "*5" } { "classname" "func_door" "angle" "0" "speed" "400" "model" "*6" } { "classname" "light_fluoro" "origin" "176 1744 -152" } { "origin" "80 1744 -152" "classname" "light_fluoro" } { "light" "250" "origin" "-232 1600 -136" "classname" "light" } { "light" "250" "classname" "light" "origin" "488 1600 -136" } { "origin" "-56 1448 72" "classname" "light" "light" "250" } { "light" "250" "classname" "light" "origin" "312 1448 72" } { "light" "260" "classname" "light_fluoro" "origin" "416 2064 -112" } { "light" "260" "origin" "416 1968 -112" "classname" "light_fluoro" } { "light" "250" "origin" "128 1880 -112" "classname" "light" } { "origin" "616 1944 -88" "classname" "light" } { "style" "10" "classname" "light_fluorospark" "origin" "344 2216 -88" } { "light" "180" "origin" "352 2016 -112" "classname" "light" } { "classname" "light" "origin" "128 2056 -112" "light" "250" } { "light" "250" "origin" "-112 1984 -112" "classname" "light" } { "light" "350" "origin" "-472 2064 -88" "classname" "light_fluoro" } { "classname" "light" "origin" "-192 2208 8" "light" "250" } { "light" "250" "origin" "-424 2208 8" "classname" "light" } { "light" "250" "origin" "-248 2088 -96" "classname" "light" } { "origin" "-200 2384 -72" "classname" "light" } { "classname" "light" "origin" "-424 2384 -72" } { "light" "200" "origin" "-448 2408 -128" "classname" "light" } { "classname" "light" "origin" "-176 2408 -128" "light" "200" } { "sounds" "1" "classname" "func_plat" "model" "*7" } { "light" "350" "origin" "-352 2656 184" "classname" "light" } { "light" "350" "classname" "light" "origin" "-352 2464 184" } { "origin" "-576 2800 -40" "classname" "light" } { "light" "500" "origin" "160 2920 232" "classname" "light" } { "classname" "light" "origin" "160 2720 232" "light" "500" } { "origin" "-288 2992 8" "classname" "light" } { "classname" "light" "origin" "-168 2776 -40" } { "classname" "light" "origin" "160 2824 104" "light" "200" } { "light" "150" "origin" "-64 2760 136" "classname" "light" } { "light" "200" "origin" "16 2832 -152" "classname" "light" } { "classname" "light" "origin" "304 2832 -152" "light" "200" } { "origin" "504 2816 16" "classname" "light" } { "sounds" "3" "wait" "-1" "speed" "600" "targetname" "t2" "spawnflags" "1" "angle" "270" "classname" "func_door" "model" "*8" } { "classname" "light" "origin" "160 2840 -152" "light" "200" } { "light" "80" "origin" "16 2904 -88" "classname" "light" } { "classname" "light" "origin" "304 2904 -88" "light" "80" } { "classname" "light" "origin" "160 2904 -88" "light" "80" } { "wait" "-1" "sounds" "1" "target" "t2" "speed" "50" "angle" "270" "classname" "func_button" "model" "*9" } { "light" "100" "origin" "0 1800 -32" "classname" "light" } { "classname" "light" "origin" "248 1800 -32" "light" "100" } { "style" "32" "targetname" "t3" "origin" "8 2352 200" "classname" "light" } { "style" "32" "targetname" "t3" "classname" "light" "origin" "32 2392 200" } { "style" "32" "targetname" "t3" "origin" "56 2352 200" "classname" "light" } { "style" "32" "targetname" "t3" "classname" "light" "origin" "32 2312 200" } { "style" "32" "targetname" "t3" "light" "200" "origin" "32 2352 88" "classname" "light" } { "spawnflags" "2048" "origin" "112 2352 16" "classname" "weapon_nailgun" } { "sounds" "3" "targetname" "t3" "spawnflags" "3" "angle" "270" "classname" "func_door_secret" "model" "*10" } { "style" "32" "sounds" "3" "target" "t3" "classname" "trigger_once" "model" "*11" } { "origin" "304 2368 96" "classname" "light" } { "angle" "180" "origin" "248 2392 40" "classname" "monster_army" } { "origin" "272 2352 64" "classname" "item_spikes" } { "style" "32" "sounds" "3" "target" "t3" "classname" "trigger_once" "model" "*12" } { "origin" "832 2608 16" "classname" "light" "light" "220" } { "light" "220" "classname" "light" "origin" "832 2480 0" } { "light" "240" "origin" "800 2816 24" "classname" "light" } { "style" "33" "targetname" "t11" "spawnflags" "1" "classname" "light" "origin" "752 2000 -88" "light" "400" } { "style" "34" "spawnflags" "1" "targetname" "t12" "origin" "1280 2000 -152" "classname" "light" "light" "400" } { "style" "35" "spawnflags" "1" "targetname" "t13" "classname" "light" "origin" "1280 2496 -216" "light" "400" } { "style" "36" "spawnflags" "1" "targetname" "t14" "origin" "784 2496 -280" "classname" "light" } { "classname" "light" "origin" "1368 2584 -488" "light" "200" } { "origin" "1368 1944 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "696 2584 -488" "light" "150" } { "origin" "1016 2584 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "1016 1944 -488" "light" "200" } { "origin" "1368 2272 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "696 2272 -488" "light" "200" } { "classname" "light" "origin" "960 2296 -488" "light" "200" } { "light" "200" "origin" "1032 2352 -488" "classname" "light" } { "classname" "light" "origin" "888 2352 -488" "light" "200" } { "light" "200" "origin" "960 2408 -488" "classname" "light" } { "light" "100" "classname" "light" "origin" "984 2448 -304" } { "classname" "light" "origin" "832 2360 112" "light" "400" } { "classname" "light" "origin" "1144 2448 -488" } { "origin" "1232 2360 -488" "classname" "light" } { "classname" "light" "origin" "1320 2448 -488" "light" "200" } { "light" "200" "origin" "1232 2536 -488" "classname" "light" } { "classname" "light" "origin" "1232 2136 -488" } { "origin" "1144 2048 -488" "classname" "light" } { "classname" "light" "origin" "1232 1960 -488" "light" "200" } { "light" "200" "origin" "1320 2048 -488" "classname" "light" } { "classname" "light" "origin" "832 2336 -200" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "sounds" "3" "model" "*13" } { "classname" "func_door_secret" "angle" "180" "sounds" "3" "model" "*14" } { "classname" "light" "origin" "552 2480 -56" "light" "200" } { "light" "200" "origin" "544 2296 -56" "classname" "light" } { "classname" "light" "origin" "664 2480 -56" "light" "200" } { "classname" "func_door" "targetname" "t4" "angle" "-2" "spawnflags" "1" "sounds" "2" "model" "*15" } { "classname" "trigger_multiple" "target" "t4" "health" "1" "model" "*16" } { "spawnflags" "2048" "classname" "func_door" "angle" "90" "targetname" "t5" "wait" "-1" "sounds" "2" "model" "*17" } { "spawnflags" "2048" "classname" "trigger_once" "target" "t5" "model" "*18" } { "classname" "item_artifact_super_damage" "origin" "544 2480 -88" } { "classname" "light" "origin" "832 2104 -208" } { "classname" "light" "origin" "832 2048 -368" "light" "150" } { "classname" "light" "origin" "1120 2464 112" } { "origin" "1120 2080 112" "classname" "light" } { "classname" "light" "origin" "752 2080 112" "light" "200" } { "classname" "light" "origin" "1048 2280 -72" } { "classname" "func_button" "angle" "270" "target" "t1" "model" "*19" } { "classname" "light" "origin" "1136 1848 -504" "light" "220" } { "origin" "1136 1672 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1008 1672 -504" "light" "220" } { "origin" "1008 1848 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1288 1848 -504" "light" "220" } { "origin" "1400 1584 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1224 1584 -504" "light" "220" } { "origin" "1400 1736 -504" "classname" "light" "light" "220" } { "origin" "880 1672 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "744 1672 -504" "light" "220" } { "classname" "light" "origin" "1312 1648 -392" "light" "220" } { "light" "170" "origin" "1312 1520 -392" "classname" "light" } { "classname" "light" "origin" "1200 1760 -392" "light" "220" } { "light" "170" "origin" "1072 1760 -392" "classname" "light" } { "classname" "light" "origin" "944 1760 -392" "light" "170" } { "origin" "832 1992 -208" "classname" "light" "light" "220" } { "origin" "744 1832 -504" "classname" "light" } { "light" "170" "origin" "832 1760 -392" "classname" "light" } { "light" "220" "origin" "680 1936 -504" "classname" "light" } { "classname" "light" "origin" "1312 1392 -352" "light" "170" } { "light" "170" "origin" "1312 1264 -288" "classname" "light" } { "classname" "light" "origin" "1312 1136 -232" } { "origin" "1224 1456 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1400 1456 -504" "light" "220" } { "origin" "1400 1328 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1224 1328 -504" "light" "220" } { "origin" "1224 1200 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1400 1200 -504" "light" "220" } { "origin" "1312 960 -208" "classname" "light" } { "classname" "trigger_teleport" "target" "t6" "model" "*20" } { "classname" "light" "origin" "1312 912 -472" } { "classname" "light" "origin" "1312 1080 -368" } { "classname" "light" "origin" "1128 1064 -504" "light" "170" } { "origin" "1128 856 -504" "classname" "light" "light" "170" } { "classname" "light" "origin" "1496 856 -504" "light" "170" } { "origin" "1496 1064 -504" "classname" "light" "light" "170" } { "classname" "light" "origin" "1312 776 -504" "light" "170" } { "spawnflags" "2" "angle" "90" "classname" "func_door_secret" "model" "*21" } { "origin" "1072 1024 -168" "classname" "light" } { "spawnflags" "1" "height" "400" "angle" "-1" "sounds" "1" "classname" "func_plat" "model" "*22" } { "targetname" "t8" "spawnflags" "2" "angle" "90" "classname" "func_door_secret" "model" "*23" } { "target" "t8" "classname" "trigger_multiple" "model" "*24" } { "light" "220" "origin" "792 888 -248" "classname" "light" } { "light" "180" "classname" "light" "origin" "944 608 -248" } { "light" "150" "origin" "792 512 -248" "classname" "light" } { "classname" "light" "origin" "792 512 -56" "light" "150" } { "classname" "light" "origin" "624 928 -240" "light" "220" } { "light" "220" "origin" "504 1200 -248" "classname" "light" } { "origin" "936 800 -248" "classname" "light" "light" "180" } { "light" "180" "classname" "light" "origin" "960 984 -208" } { "classname" "light" "origin" "792 512 128" "light" "150" } { "spawnflags" "2" "origin" "944 1008 -272" "classname" "item_health" } { "spawnflags" "1792" "origin" "144 2352 16" "classname" "weapon_rocketlauncher" } { "spawnflags" "1792" "origin" "1216 1040 -432" "classname" "weapon_grenadelauncher" } { "spawnflags" "1793" "origin" "1392 1024 -432" "classname" "item_rockets" } { "targetname" "t6" "origin" "-32 1800 -56" "classname" "info_teleport_destination" } { "spawnflags" "1792" "origin" "832 2448 -368" "classname" "weapon_supernailgun" } { "spawnflags" "1792" "origin" "128 1216 -208" "classname" "weapon_supershotgun" } { "origin" "296 2136 -192" "classname" "item_shells" } { "spawnflags" "1" "origin" "1424 904 -432" "classname" "item_health" } { "classname" "item_health" "origin" "1376 808 -432" } { "origin" "1176 936 -432" "classname" "item_health" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*25" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*26" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*27" } { "target" "t10" "targetname" "t9" "count" "3" "classname" "trigger_counter" "model" "*28" } { "message" "You must press the three buttons..." "spawnflags" "2048" "sounds" "2" "wait" "-1" "targetname" "t10" "angle" "180" "classname" "func_door" "model" "*29" } { "light" "150" "origin" "832 1928 -384" "classname" "light" } { "style" "33" "sounds" "3" "target" "t11" "classname" "trigger_once" "model" "*30" } { "style" "34" "sounds" "3" "target" "t12" "classname" "trigger_once" "model" "*31" } { "style" "35" "sounds" "3" "target" "t13" "classname" "trigger_once" "model" "*32" } { "style" "36" "sounds" "3" "target" "t14" "classname" "trigger_once" "model" "*33" } { "sounds" "1" "wait" "-1" "targetname" "t11" "spawnflags" "1" "angle" "-2" "classname" "func_door" "model" "*34" } { "targetname" "t12" "classname" "func_door" "angle" "-2" "spawnflags" "1" "wait" "-1" "sounds" "1" "model" "*35" } { "targetname" "t13" "sounds" "1" "wait" "-1" "spawnflags" "1" "angle" "-2" "classname" "func_door" "model" "*36" } { "targetname" "t14" "classname" "func_door" "angle" "-2" "spawnflags" "1" "wait" "-1" "sounds" "1" "model" "*37" } { "angle" "90" "origin" "1312 880 -248" "classname" "info_player_deathmatch" } { "spawnflags" "1" "origin" "1376 1024 -272" "classname" "item_spikes" } { "origin" "1184 992 -272" "classname" "item_health" } { "spawnflags" "1" "origin" "1376 856 -272" "classname" "item_health" } { "spawnflags" "1" "origin" "1256 1704 -432" "classname" "item_health" } { "angle" "90" "origin" "480 48 24" "classname" "info_player_deathmatch" } { "angle" "180" "origin" "528 1888 -168" "classname" "info_player_deathmatch" } { "angle" "0" "origin" "-272 2928 -56" "classname" "info_player_deathmatch" } { "angle" "0" "origin" "832 2048 -152" "classname" "info_player_deathmatch" } { "speed" "300" "message" "This door opens elsewhere..." "spawnflags" "2048" "targetname" "t15" "angle" "270" "classname" "func_door" "wait" "-1" "model" "*38" } { "spawnflags" "2048" "target" "t15" "classname" "trigger_once" "model" "*39" } { "spawnflags" "1792" "origin" "480 576 0" "classname" "weapon_nailgun" } { "spawnflags" "1793" "origin" "464 728 64" "classname" "item_spikes" } { "origin" "328 848 -224" "classname" "item_health" } { "classname" "item_health" "origin" "344 920 -224" } { "spawnflags" "1" "origin" "-16 2064 -208" "classname" "item_health" } { "spawnflags" "1792" "origin" "-480 2240 -160" "classname" "item_rockets" } { "spawnflags" "1793" "origin" "-96 2456 16" "classname" "item_shells" } { "classname" "item_rockets" "origin" "-104 2216 16" "spawnflags" "1793" } { "classname" "item_artifact_invulnerability" "origin" "256 1808 -40" "spawnflags" "1792" } { "classname" "monster_army" "origin" "0 576 24" "angle" "0" "spawnflags" "256" } { "classname" "monster_army" "origin" "8 1520 -200" "angle" "270" } { "classname" "monster_dog" "origin" "88 1520 -200" "angle" "270" } { "classname" "monster_army" "origin" "224 1552 -200" "angle" "270" "spawnflags" "768" } { "spawnflags" "768" "angle" "270" "origin" "-8 936 -200" "classname" "monster_army" } { "classname" "monster_army" "origin" "648 736 104" "spawnflags" "768" "angle" "180" } { "classname" "item_artifact_envirosuit" "origin" "712 2040 -408" "angle" "90" } { "classname" "light" "origin" "712 2040 -360" "light" "100" } { "classname" "item_rockets" "origin" "1328 2536 -528" "spawnflags" "1793" } { "classname" "item_health" "origin" "916 2416 -136" "spawnflags" "2" } { "spawnflags" "1" "classname" "monster_army" "origin" "1312 936 -248" "angle" "90" } { "classname" "monster_dog" "origin" "1336 1784 -408" "angle" "180" "spawnflags" "257" } { "spawnflags" "257" "angle" "90" "origin" "1392 928 -248" "classname" "monster_army" } { "classname" "monster_army" "origin" "1384 1008 -248" "angle" "90" "spawnflags" "768" } { "spawnflags" "768" "angle" "90" "origin" "1240 1008 -248" "classname" "monster_army" } { "classname" "monster_army" "origin" "1256 1760 -408" "angle" "180" "spawnflags" "257" } { "classname" "monster_army" "origin" "824 1784 -408" "spawnflags" "257" "angle" "90" } { "classname" "monster_dog" "origin" "1128 1760 -408" "angle" "180" "spawnflags" "769" } { "classname" "path_corner" "origin" "880 2048 -168" "target" "t16" "targetname" "t17" } { "origin" "1232 2048 -232" "classname" "path_corner" "targetname" "t16" "target" "t17" } { "classname" "monster_army" "origin" "1232 2088 -216" "target" "t16" } { "classname" "monster_army" "origin" "1232 2448 -280" "angle" "270" "spawnflags" "256" } { "classname" "monster_army" "origin" "832 2464 -344" "angle" "0" "spawnflags" "256" } { "classname" "monster_army" "origin" "832 2072 -408" "angle" "90" } { "classname" "monster_dog" "origin" "840 1960 -408" "angle" "90" "spawnflags" "768" } { "classname" "trigger_multiple" "target" "t18" "health" "1" "model" "*40" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "targetname" "t18" "model" "*41" } { "classname" "weapon_supershotgun" "origin" "-360 2912 -80" } { "classname" "trigger_multiple" "target" "t18" "model" "*42" } { "classname" "light" "origin" "-352 2912 -24" "light" "120" } { "classname" "light" "origin" "160 3024 0" "light" "120" } { "classname" "item_shells" "origin" "528 720 80" } { "classname" "monster_army" "origin" "416 1912 -168" "angle" "180" "spawnflags" "768" } { "classname" "monster_dog" "origin" "432 2120 -168" "angle" "180" "spawnflags" "256" } { "classname" "path_corner" "origin" "248 1992 -200" "targetname" "t19" "target" "t20" } { "origin" "-200 1992 -200" "classname" "path_corner" "targetname" "t20" "target" "t21" } { "classname" "path_corner" "origin" "-136 1912 -200" "targetname" "t21" "target" "t22" } { "origin" "248 1912 -200" "classname" "path_corner" "target" "t19" "targetname" "t22" } { "classname" "monster_army" "origin" "80 2024 -184" "target" "t20" } { "classname" "monster_army" "origin" "-16 1888 -184" "spawnflags" "256" "target" "t22" } { "classname" "monster_dog" "origin" "-248 2144 -136" "spawnflags" "768" "angle" "315" } { "classname" "path_corner" "origin" "-560 2352 40" "targetname" "t23" "target" "t24" } { "origin" "-104 2352 40" "classname" "path_corner" "target" "t23" "targetname" "t24" } { "classname" "monster_army" "origin" "-432 2352 56" "spawnflags" "768" "target" "t23" } { "angle" "0" "classname" "monster_dog" "origin" "-544 2584 56" "spawnflags" "256" } { "classname" "monster_army" "origin" "-344 2656 -104" "angle" "270" } { "classname" "monster_dog" "origin" "-72 2896 -56" "spawnflags" "256" "angle" "225" } { "classname" "monster_army" "origin" "432 2920 -56" "target" "t25" } { "classname" "monster_army" "origin" "424 2832 -56" "spawnflags" "256" "angle" "180" } { "classname" "path_corner" "origin" "368 2936 -72" "targetname" "t25" "target" "t26" } { "origin" "368 2696 -72" "classname" "path_corner" "targetname" "t26" "target" "t27" } { "classname" "path_corner" "origin" "480 2696 -72" "targetname" "t27" "target" "t28" } { "origin" "480 2936 -72" "classname" "path_corner" "target" "t25" "targetname" "t28" } { "classname" "monster_army" "origin" "424 2672 -56" "target" "t27" } { "classname" "monster_army" "origin" "424 2880 -56" "angle" "180" "spawnflags" "768" } { "classname" "monster_army" "origin" "424 2760 -56" "spawnflags" "768" "angle" "180" } { "classname" "path_corner" "origin" "832 2712 -88" "targetname" "t29" "target" "t30" } { "origin" "832 2416 -104" "classname" "path_corner" "target" "t29" "targetname" "t30" } { "classname" "monster_army" "origin" "848 2584 -72" "spawnflags" "257" "target" "t29" } { "classname" "monster_army" "origin" "824 2008 -152" "angle" "90" "spawnflags" "768" } { "classname" "item_health" "origin" "-376 1704 -224" "spawnflags" "1" } { "angle" "180" "spawnflags" "768" "origin" "248 2352 40" "classname" "monster_army" } { "spawnflags" "768" "angle" "270" "origin" "-72 2464 40" "classname" "monster_army" } { "spawnflags" "768" "angle" "225" "origin" "904 1024 -248" "classname" "monster_army" } { "light" "100" "style" "10" "classname" "light" "origin" "688 0 80" } { "message" "Shoot this secret door..." "spawnflags" "1" "angle" "0" "classname" "func_door_secret" "model" "*43" } { "origin" "672 -40 48" "classname" "item_shells" } { "classname" "trigger_secret" "model" "*44" } { "classname" "trigger_secret" "model" "*45" } { "classname" "trigger_secret" "model" "*46" } { "classname" "trigger_secret" "model" "*47" } { "classname" "trigger_secret" "model" "*48" } { "classname" "trigger_secret" "model" "*49" } { "light" "100" "origin" "0 632 -88" "classname" "light" } { "classname" "item_health" "origin" "600 2200 -128" "spawnflags" "1" } { "light" "220" "classname" "light" "origin" "832 1880 -504" } { "origin" "72 2056 -208" "classname" "misc_explobox" } { "light" "200" "origin" "-128 584 72" "classname" "light" } { "light" "200" "origin" "-128 568 -136" "classname" "light" } { "light" "100" "origin" "-56 632 -168" "classname" "light" } { "light" "200" "origin" "-56 864 -136" "classname" "light" } { "light" "200" "origin" "40 1672 -40" "classname" "light" } { "classname" "light" "origin" "216 1672 -40" "light" "200" } { "classname" "light" "origin" "128 1080 -152" "light" "200" } { "light" "200" "origin" "128 1096 72" "classname" "light" } { "light" "250" "classname" "light" "origin" "-352 1656 72" } { "origin" "608 1640 72" "classname" "light" "light" "250" } { "origin" "-48 1144 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "-48 1256 -320" } { "origin" "320 1256 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "312 1128 -320" } { "origin" "136 1128 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "136 1272 -320" } { "spawnflags" "3072" "wait" "5" "sounds" "2" "message" "You can jump across..." "classname" "trigger_multiple" "targetname" "t32" "model" "*50" } { "spawnflags" "3072" "wait" "5" "message" "You can jump up here..." "sounds" "2" "classname" "trigger_multiple" "targetname" "t31" "model" "*51" } { "light" "150" "origin" "1008 2128 -408" "classname" "light" } { "light" "250" "origin" "1312 544 -184" "classname" "light" } { "light" "200" "classname" "light" "origin" "1208 456 -184" } { "origin" "1416 456 -184" "classname" "light" "light" "200" } { "light" "170" "origin" "1312 728 -56" "classname" "light" } { "map" "e1m2" "classname" "trigger_changelevel" "model" "*52" } { "classname" "item_health" "origin" "1224 2464 -304" "spawnflags" "1" } { "classname" "light" "origin" "688 1680 -160" "light" "160" } { "light" "160" "origin" "-392 1688 -160" "classname" "light" } { "spawnflags" "768" "angle" "270" "origin" "288 1536 -200" "classname" "monster_army" } { "spawnflags" "768" "origin" "968 2432 -112" "classname" "monster_army" } { "wait" "5" "message" "Walk into the slipgate to exit." "classname" "trigger_multiple" "sounds" "2" "angle" "270" "model" "*53" } { "classname" "trigger_once" "killtarget" "t31" "target" "t31" "spawnflags" "3072" "model" "*54" } { "classname" "trigger_once" "spawnflags" "3072" "target" "t32" "killtarget" "t32" "model" "*55" } { "classname" "item_armor2" "origin" "1312 1048 -432" } { "classname" "ambient_comp_hum" "origin" "250 194 72" } { "origin" "714 194 72" "classname" "ambient_comp_hum" } { "classname" "ambient_comp_hum" "origin" "626 2058 -104" } { "origin" "466 2226 -104" "classname" "ambient_comp_hum" } { "classname" "info_intermission" "origin" "-112 704 56" "mangle" "20 45 0" } { "classname" "info_intermission" "origin" "-208 2736 192" "mangle" "20 225 0" } { "classname" "info_intermission" "origin" "240 2664 104" "mangle" "20 120 0" } { "classname" "info_intermission" "origin" "1376 1936 64" "mangle" "20 135 0" } { "angle" "90" "origin" "528 -296 72" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "432 -296 72" "angle" "90" } { "angle" "90" "origin" "480 -240 72" "classname" "info_player_coop" } { "classname" "func_wall" "spawnflags" "1792" "model" "*56" } { "classname" "func_wall" "spawnflags" "1792" "model" "*57" } { "classname" "ambient_drone" "origin" "1314 450 -200" } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e1m1.ent���������������������������������������������������������0000644�0000000�0000000�00000063336�12403131422�017040� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "worldtype" "2" "sounds" "6" "classname" "worldspawn" "wad" "gfx/base.wad" "message" "the Slipgate Complex" } { "classname" "info_player_start" "origin" "480 -352 88" "angle" "90" } { "classname" "light" "origin" "480 96 168" "light" "250" } { "classname" "light" "origin" "480 288 168" "light" "250" } { "classname" "light" "origin" "272 96 80" } { "origin" "272 288 80" "classname" "light" } { "classname" "light" "origin" "272 192 80" } { "origin" "688 192 80" "classname" "light_fluorospark" "style" "10" } { "style" "10" "classname" "light" "origin" "688 288 80" } { "origin" "688 96 80" "classname" "light" "style" "10" } { "classname" "light" "origin" "480 -280 168" "light" "200" } { "origin" "480 -144 168" "classname" "light" "light" "200" } { "classname" "light" "origin" "480 -376 120" "light" "200" } { "light" "160" "origin" "480 -40 168" "classname" "light" } { "speed" "400" "sounds" "2" "angle" "270" "classname" "func_door" "model" "*1" } { "speed" "400" "angle" "90" "classname" "func_door" "model" "*2" } { "light" "250" "origin" "592 544 88" "classname" "light_fluoro" } { "origin" "456 600 104" "classname" "light" } { "light" "180" "origin" "688 648 136" "classname" "light" } { "classname" "light" "origin" "688 520 136" "light" "180" } { "origin" "688 480 80" "classname" "item_armor1" } { "angle" "180" "spawnflags" "768" "origin" "616 72 40" "classname" "monster_army" } { "light" "250" "origin" "0 576 120" "classname" "light" } { "light" "180" "origin" "160 576 72" "classname" "light" } { "light" "200" "origin" "560 -32 72" "classname" "light" } { "light" "200" "classname" "light" "origin" "400 -32 72" } { "light" "200" "origin" "0 712 72" "classname" "light" } { "classname" "light" "origin" "0 728 -136" "light" "200" } { "light" "200" "origin" "0 592 -136" "classname" "light" } { "wait" "5" "angle" "-2" "sounds" "2" "targetname" "t1" "classname" "func_door" "dmg" "10" "model" "*3" } { "sounds" "1" "target" "t1" "angle" "180" "classname" "func_button" "model" "*4" } { "light" "200" "origin" "412 780 136" "classname" "light" } { "light" "200" "classname" "light" "origin" "328 904 72" } { "light" "200" "origin" "168 800 72" "classname" "light" } { "light" "200" "classname" "light" "origin" "-72 864 72" } { "origin" "264 888 -136" "classname" "light" } { "classname" "light" "origin" "-8 992 -136" "light" "200" } { "light" "250" "classname" "light" "origin" "272 1064 -136" } { "light" "250" "origin" "-8 1232 -136" "classname" "light" } { "light" "250" "classname" "light" "origin" "256 1272 -136" } { "light" "250" "origin" "312 1464 -136" "classname" "light" } { "light" "200" "origin" "128 968 72" "classname" "light" } { "light" "250" "classname" "light" "origin" "-48 1168 72" } { "light" "250" "origin" "312 1168 72" "classname" "light" } { "light" "220" "classname" "light" "origin" "128 1504 -120" } { "light" "250" "classname" "light" "origin" "-56 1464 -136" } { "sounds" "2" "classname" "func_door" "angle" "180" "speed" "400" "model" "*5" } { "classname" "func_door" "angle" "0" "speed" "400" "model" "*6" } { "classname" "light_fluoro" "origin" "176 1744 -152" } { "origin" "80 1744 -152" "classname" "light_fluoro" } { "light" "250" "origin" "-232 1600 -136" "classname" "light" } { "light" "250" "classname" "light" "origin" "488 1600 -136" } { "origin" "-56 1448 72" "classname" "light" "light" "250" } { "light" "250" "classname" "light" "origin" "312 1448 72" } { "light" "260" "classname" "light_fluoro" "origin" "416 2064 -112" } { "light" "260" "origin" "416 1968 -112" "classname" "light_fluoro" } { "light" "250" "origin" "128 1880 -112" "classname" "light" } { "origin" "616 1944 -88" "classname" "light" } { "style" "10" "classname" "light_fluorospark" "origin" "344 2216 -88" } { "light" "180" "origin" "352 2016 -112" "classname" "light" } { "classname" "light" "origin" "128 2056 -112" "light" "250" } { "light" "250" "origin" "-112 1984 -112" "classname" "light" } { "light" "350" "origin" "-472 2064 -88" "classname" "light_fluoro" } { "classname" "light" "origin" "-192 2208 8" "light" "250" } { "light" "250" "origin" "-424 2208 8" "classname" "light" } { "light" "250" "origin" "-248 2088 -96" "classname" "light" } { "origin" "-200 2384 -72" "classname" "light" } { "classname" "light" "origin" "-424 2384 -72" } { "light" "200" "origin" "-448 2408 -128" "classname" "light" } { "classname" "light" "origin" "-176 2408 -128" "light" "200" } { "sounds" "1" "classname" "func_plat" "model" "*7" } { "light" "350" "origin" "-352 2656 184" "classname" "light" } { "light" "350" "classname" "light" "origin" "-352 2464 184" } { "origin" "-576 2800 -40" "classname" "light" } { "light" "500" "origin" "160 2920 232" "classname" "light" } { "classname" "light" "origin" "160 2720 232" "light" "500" } { "origin" "-288 2992 8" "classname" "light" } { "classname" "light" "origin" "-168 2776 -40" } { "classname" "light" "origin" "160 2824 104" "light" "200" } { "light" "150" "origin" "-64 2760 136" "classname" "light" } { "light" "200" "origin" "16 2832 -152" "classname" "light" } { "classname" "light" "origin" "304 2832 -152" "light" "200" } { "origin" "504 2816 16" "classname" "light" } { "sounds" "3" "wait" "-1" "speed" "600" "targetname" "t2" "spawnflags" "1" "angle" "270" "classname" "func_door" "model" "*8" } { "classname" "light" "origin" "160 2840 -152" "light" "200" } { "light" "80" "origin" "16 2904 -88" "classname" "light" } { "classname" "light" "origin" "304 2904 -88" "light" "80" } { "classname" "light" "origin" "160 2904 -88" "light" "80" } { "wait" "-1" "sounds" "1" "target" "t2" "speed" "50" "angle" "270" "classname" "func_button" "model" "*9" } { "light" "100" "origin" "0 1800 -32" "classname" "light" } { "classname" "light" "origin" "248 1800 -32" "light" "100" } { "style" "32" "targetname" "t3" "origin" "8 2352 200" "classname" "light" } { "style" "32" "targetname" "t3" "classname" "light" "origin" "32 2392 200" } { "style" "32" "targetname" "t3" "origin" "56 2352 200" "classname" "light" } { "style" "32" "targetname" "t3" "classname" "light" "origin" "32 2312 200" } { "style" "32" "targetname" "t3" "light" "200" "origin" "32 2352 88" "classname" "light" } { "spawnflags" "2048" "origin" "112 2352 16" "classname" "weapon_nailgun" } { "sounds" "3" "targetname" "t3" "spawnflags" "3" "angle" "270" "classname" "func_door_secret" "model" "*10" } { "style" "32" "sounds" "3" "target" "t3" "classname" "trigger_once" "model" "*11" } { "origin" "304 2368 96" "classname" "light" } { "angle" "180" "origin" "248 2392 40" "classname" "monster_army" } { "origin" "272 2352 64" "classname" "item_spikes" } { "style" "32" "sounds" "3" "target" "t3" "classname" "trigger_once" "model" "*12" } { "origin" "832 2608 16" "classname" "light" "light" "220" } { "light" "220" "classname" "light" "origin" "832 2480 0" } { "light" "240" "origin" "800 2816 24" "classname" "light" } { "style" "33" "targetname" "t11" "spawnflags" "1" "classname" "light" "origin" "752 2000 -88" "light" "400" } { "style" "34" "spawnflags" "1" "targetname" "t12" "origin" "1280 2000 -152" "classname" "light" "light" "400" } { "style" "35" "spawnflags" "1" "targetname" "t13" "classname" "light" "origin" "1280 2496 -216" "light" "400" } { "style" "36" "spawnflags" "1" "targetname" "t14" "origin" "784 2496 -280" "classname" "light" } { "classname" "light" "origin" "1368 2584 -488" "light" "200" } { "origin" "1368 1944 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "696 2584 -488" "light" "150" } { "origin" "1016 2584 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "1016 1944 -488" "light" "200" } { "origin" "1368 2272 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "696 2272 -488" "light" "200" } { "classname" "light" "origin" "960 2296 -488" "light" "200" } { "light" "200" "origin" "1032 2352 -488" "classname" "light" } { "classname" "light" "origin" "888 2352 -488" "light" "200" } { "light" "200" "origin" "960 2408 -488" "classname" "light" } { "light" "100" "classname" "light" "origin" "984 2448 -304" } { "classname" "light" "origin" "832 2360 112" "light" "400" } { "classname" "light" "origin" "1144 2448 -488" } { "origin" "1232 2360 -488" "classname" "light" } { "classname" "light" "origin" "1320 2448 -488" "light" "200" } { "light" "200" "origin" "1232 2536 -488" "classname" "light" } { "classname" "light" "origin" "1232 2136 -488" } { "origin" "1144 2048 -488" "classname" "light" } { "classname" "light" "origin" "1232 1960 -488" "light" "200" } { "light" "200" "origin" "1320 2048 -488" "classname" "light" } { "classname" "light" "origin" "832 2336 -200" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "sounds" "3" "model" "*13" } { "classname" "func_door_secret" "angle" "180" "sounds" "3" "model" "*14" } { "classname" "light" "origin" "552 2480 -56" "light" "200" } { "light" "200" "origin" "544 2296 -56" "classname" "light" } { "classname" "light" "origin" "664 2480 -56" "light" "200" } { "classname" "func_door" "targetname" "t4" "angle" "-2" "spawnflags" "1" "sounds" "2" "model" "*15" "lip" "7" // svdijk -- added to prevent z-fighting } { "classname" "trigger_multiple" "target" "t4" "health" "1" "model" "*16" } { "spawnflags" "2048" "classname" "func_door" "angle" "90" "targetname" "t5" "wait" "-1" "sounds" "2" "model" "*17" } { "spawnflags" "2048" "classname" "trigger_once" "target" "t5" "model" "*18" } { "classname" "item_artifact_super_damage" "origin" "544 2480 -88" } { "classname" "light" "origin" "832 2104 -208" } { "classname" "light" "origin" "832 2048 -368" "light" "150" } { "classname" "light" "origin" "1120 2464 112" } { "origin" "1120 2080 112" "classname" "light" } { "classname" "light" "origin" "752 2080 112" "light" "200" } { "classname" "light" "origin" "1048 2280 -72" } { "classname" "func_button" "angle" "270" "target" "t1" "model" "*19" } { "classname" "light" "origin" "1136 1848 -504" "light" "220" } { "origin" "1136 1672 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1008 1672 -504" "light" "220" } { "origin" "1008 1848 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1288 1848 -504" "light" "220" } { "origin" "1400 1584 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1224 1584 -504" "light" "220" } { "origin" "1400 1736 -504" "classname" "light" "light" "220" } { "origin" "880 1672 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "744 1672 -504" "light" "220" } { "classname" "light" "origin" "1312 1648 -392" "light" "220" } { "light" "170" "origin" "1312 1520 -392" "classname" "light" } { "classname" "light" "origin" "1200 1760 -392" "light" "220" } { "light" "170" "origin" "1072 1760 -392" "classname" "light" } { "classname" "light" "origin" "944 1760 -392" "light" "170" } { "origin" "832 1992 -208" "classname" "light" "light" "220" } { "origin" "744 1832 -504" "classname" "light" } { "light" "170" "origin" "832 1760 -392" "classname" "light" } { "light" "220" "origin" "680 1936 -504" "classname" "light" } { "classname" "light" "origin" "1312 1392 -352" "light" "170" } { "light" "170" "origin" "1312 1264 -288" "classname" "light" } { "classname" "light" "origin" "1312 1136 -232" } { "origin" "1224 1456 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1400 1456 -504" "light" "220" } { "origin" "1400 1328 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1224 1328 -504" "light" "220" } { "origin" "1224 1200 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1400 1200 -504" "light" "220" } { "origin" "1312 960 -208" "classname" "light" } { "classname" "trigger_teleport" "target" "t6" "model" "*20" } { "classname" "light" "origin" "1312 912 -472" } { "classname" "light" "origin" "1312 1080 -368" } { "classname" "light" "origin" "1128 1064 -504" "light" "170" } { "origin" "1128 856 -504" "classname" "light" "light" "170" } { "classname" "light" "origin" "1496 856 -504" "light" "170" } { "origin" "1496 1064 -504" "classname" "light" "light" "170" } { "classname" "light" "origin" "1312 776 -504" "light" "170" } { "spawnflags" "2" "angle" "90" "classname" "func_door_secret" "model" "*21" } { "origin" "1072 1024 -168" "classname" "light" } { "spawnflags" "1" "height" "400" "angle" "-1" "sounds" "1" "classname" "func_plat" "model" "*22" } { "targetname" "t8" "spawnflags" "2" "angle" "90" "classname" "func_door_secret" "model" "*23" } { "target" "t8" "classname" "trigger_multiple" "model" "*24" } { "light" "220" "origin" "792 888 -248" "classname" "light" } { "light" "180" "classname" "light" "origin" "944 608 -248" } { "light" "150" "origin" "792 512 -248" "classname" "light" } { "classname" "light" "origin" "792 512 -56" "light" "150" } { "classname" "light" "origin" "624 928 -240" "light" "220" } { "light" "220" "origin" "504 1200 -248" "classname" "light" } { "origin" "936 800 -248" "classname" "light" "light" "180" } { "light" "180" "classname" "light" "origin" "960 984 -208" } { "classname" "light" "origin" "792 512 128" "light" "150" } { "spawnflags" "2" "origin" "944 1008 -272" "classname" "item_health" } { "spawnflags" "1792" "origin" "144 2352 16" "classname" "weapon_rocketlauncher" } { "spawnflags" "1792" "origin" "1216 1040 -432" "classname" "weapon_grenadelauncher" } { "spawnflags" "1793" "origin" "1392 1024 -432" "classname" "item_rockets" } { "targetname" "t6" "origin" "-32 1800 -56" "classname" "info_teleport_destination" } { "spawnflags" "1792" "origin" "832 2448 -368" "classname" "weapon_supernailgun" } { "spawnflags" "1792" "origin" "128 1216 -208" "classname" "weapon_supershotgun" } { "origin" "296 2136 -192" "classname" "item_shells" } { "spawnflags" "1" "origin" "1424 904 -432" "classname" "item_health" } { "classname" "item_health" "origin" "1376 808 -432" } { "origin" "1176 936 -432" "classname" "item_health" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*25" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*26" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*27" } { "target" "t10" "targetname" "t9" "count" "3" "classname" "trigger_counter" "model" "*28" } { "message" "You must press the three buttons..." "spawnflags" "2048" "sounds" "2" "wait" "-1" "targetname" "t10" "angle" "180" "classname" "func_door" "model" "*29" } { "light" "150" "origin" "832 1928 -384" "classname" "light" } { "style" "33" "sounds" "3" "target" "t11" "classname" "trigger_once" "model" "*30" } { "style" "34" "sounds" "3" "target" "t12" "classname" "trigger_once" "model" "*31" } { "style" "35" "sounds" "3" "target" "t13" "classname" "trigger_once" "model" "*32" } { "style" "36" "sounds" "3" "target" "t14" "classname" "trigger_once" "model" "*33" } { "sounds" "1" "wait" "-1" "targetname" "t11" "spawnflags" "1" "angle" "-2" "classname" "func_door" "model" "*34" } { "targetname" "t12" "classname" "func_door" "angle" "-2" "spawnflags" "1" "wait" "-1" "sounds" "1" "model" "*35" } { "targetname" "t13" "sounds" "1" "wait" "-1" "spawnflags" "1" "angle" "-2" "classname" "func_door" "model" "*36" } { "targetname" "t14" "classname" "func_door" "angle" "-2" "spawnflags" "1" "wait" "-1" "sounds" "1" "model" "*37" } { "angle" "90" "origin" "1312 880 -248" "classname" "info_player_deathmatch" } { "spawnflags" "1" "origin" "1376 1024 -272" "classname" "item_spikes" } { "origin" "1184 992 -272" "classname" "item_health" } { "spawnflags" "1" "origin" "1376 856 -272" "classname" "item_health" } { "spawnflags" "1" "origin" "1256 1704 -432" "classname" "item_health" } { "angle" "90" "origin" "480 48 24" "classname" "info_player_deathmatch" } { "angle" "180" "origin" "528 1888 -168" "classname" "info_player_deathmatch" } { "angle" "0" "origin" "-272 2928 -56" "classname" "info_player_deathmatch" } { "angle" "0" "origin" "832 2048 -152" "classname" "info_player_deathmatch" } { "speed" "300" "message" "This door opens elsewhere..." "spawnflags" "2048" "targetname" "t15" "angle" "270" "classname" "func_door" "wait" "-1" "model" "*38" } { "spawnflags" "2048" "target" "t15" "classname" "trigger_once" "model" "*39" } { "spawnflags" "1792" "origin" "480 576 0" "classname" "weapon_nailgun" } { "spawnflags" "1793" "origin" "464 728 64" "classname" "item_spikes" } { "origin" "328 848 -224" "classname" "item_health" } { "classname" "item_health" "origin" "344 920 -224" } { "spawnflags" "1" "origin" "-16 2064 -208" "classname" "item_health" } { "spawnflags" "1792" "origin" "-480 2240 -160" "classname" "item_rockets" } { "spawnflags" "1793" "origin" "-96 2456 16" "classname" "item_shells" } { "classname" "item_rockets" "origin" "-104 2216 16" "spawnflags" "1793" } { "classname" "item_artifact_invulnerability" "origin" "256 1808 -40" "spawnflags" "1792" } { "classname" "monster_army" "origin" "0 576 24" "angle" "0" "spawnflags" "256" } { "classname" "monster_army" "origin" "8 1520 -200" "angle" "270" } { "classname" "monster_dog" "origin" "88 1520 -200" "angle" "270" } { "classname" "monster_army" "origin" "224 1552 -200" "angle" "270" "spawnflags" "768" } { "spawnflags" "768" "angle" "270" "origin" "-8 936 -200" "classname" "monster_army" } { "classname" "monster_army" "origin" "648 736 104" "spawnflags" "768" "angle" "180" } { "classname" "item_artifact_envirosuit" "origin" "712 2040 -408" "angle" "90" } { "classname" "light" "origin" "712 2040 -360" "light" "100" } { "classname" "item_rockets" "origin" "1328 2536 -528" "spawnflags" "1793" } { "classname" "item_health" "origin" "916 2416 -136" "spawnflags" "2" } { "spawnflags" "1" "classname" "monster_army" "origin" "1312 936 -248" "angle" "90" } { "classname" "monster_dog" "origin" "1336 1784 -408" "angle" "180" "spawnflags" "257" } { "spawnflags" "257" "angle" "90" "origin" "1392 928 -248" "classname" "monster_army" } { "classname" "monster_army" "origin" "1384 1008 -248" "angle" "90" "spawnflags" "768" } { "spawnflags" "768" "angle" "90" "origin" "1240 1008 -248" "classname" "monster_army" } { "classname" "monster_army" "origin" "1256 1760 -408" "angle" "180" "spawnflags" "257" } { "classname" "monster_army" "origin" "824 1784 -408" "spawnflags" "257" "angle" "90" } { "classname" "monster_dog" "origin" "1128 1760 -408" "angle" "180" "spawnflags" "769" } { "classname" "path_corner" "origin" "880 2048 -168" "target" "t16" "targetname" "t17" } { "origin" "1232 2048 -232" "classname" "path_corner" "targetname" "t16" "target" "t17" } { "classname" "monster_army" "origin" "1232 2088 -216" "target" "t16" } { "classname" "monster_army" "origin" "1232 2448 -280" "angle" "270" "spawnflags" "256" } { "classname" "monster_army" "origin" "832 2464 -344" "angle" "0" "spawnflags" "256" } { "classname" "monster_army" "origin" "832 2072 -408" "angle" "90" } { "classname" "monster_dog" "origin" "840 1960 -408" "angle" "90" "spawnflags" "768" } { "classname" "trigger_multiple" "target" "t18" "health" "1" "model" "*40" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "targetname" "t18" "model" "*41" } { "classname" "weapon_supershotgun" "origin" "-360 2912 -80" } { "classname" "trigger_multiple" "target" "t18" "model" "*42" } { "classname" "light" "origin" "-352 2912 -24" "light" "120" } { "classname" "light" "origin" "160 3024 0" "light" "120" } { "classname" "item_shells" "origin" "528 720 80" } { "classname" "monster_army" "origin" "416 1912 -168" "angle" "180" "spawnflags" "768" } { "classname" "monster_dog" "origin" "432 2120 -168" "angle" "180" "spawnflags" "256" } { "classname" "path_corner" "origin" "248 1992 -200" "targetname" "t19" "target" "t20" } { "origin" "-200 1992 -200" "classname" "path_corner" "targetname" "t20" "target" "t21" } { "classname" "path_corner" "origin" "-136 1912 -200" "targetname" "t21" "target" "t22" } { "origin" "248 1912 -200" "classname" "path_corner" "target" "t19" "targetname" "t22" } { "classname" "monster_army" "origin" "80 2024 -184" "target" "t20" } { "classname" "monster_army" "origin" "-16 1888 -184" "spawnflags" "256" "target" "t22" } { "classname" "monster_dog" "origin" "-248 2144 -136" "spawnflags" "768" "angle" "315" } { "classname" "path_corner" "origin" "-560 2352 40" "targetname" "t23" "target" "t24" } { "origin" "-104 2352 40" "classname" "path_corner" "target" "t23" "targetname" "t24" } { "classname" "monster_army" "origin" "-432 2352 56" "spawnflags" "768" "target" "t23" } { "angle" "0" "classname" "monster_dog" "origin" "-544 2584 56" "spawnflags" "256" } { "classname" "monster_army" "origin" "-344 2656 -104" "angle" "270" } { "classname" "monster_dog" "origin" "-72 2896 -56" "spawnflags" "256" "angle" "225" } { "classname" "monster_army" "origin" "432 2920 -56" "target" "t25" } { "classname" "monster_army" "origin" "424 2832 -56" "spawnflags" "256" "angle" "180" } { "classname" "path_corner" "origin" "368 2936 -72" "targetname" "t25" "target" "t26" } { "origin" "368 2696 -72" "classname" "path_corner" "targetname" "t26" "target" "t27" } { "classname" "path_corner" "origin" "480 2696 -72" "targetname" "t27" "target" "t28" } { "origin" "480 2936 -72" "classname" "path_corner" "target" "t25" "targetname" "t28" } { "classname" "monster_army" "origin" "424 2672 -56" "target" "t27" } { "classname" "monster_army" "origin" "424 2880 -56" "angle" "180" "spawnflags" "768" } { "classname" "monster_army" "origin" "424 2760 -56" "spawnflags" "768" "angle" "180" } { "classname" "path_corner" "origin" "832 2712 -88" "targetname" "t29" "target" "t30" } { "origin" "832 2416 -104" "classname" "path_corner" "target" "t29" "targetname" "t30" } { "classname" "monster_army" "origin" "848 2584 -72" "spawnflags" "257" "target" "t29" } { "classname" "monster_army" "origin" "824 2008 -152" "angle" "90" "spawnflags" "768" } { "classname" "item_health" "origin" "-376 1704 -224" "spawnflags" "1" } { "angle" "180" "spawnflags" "768" "origin" "248 2352 40" "classname" "monster_army" } { "spawnflags" "768" "angle" "270" "origin" "-72 2464 40" "classname" "monster_army" } { "spawnflags" "768" "angle" "225" "origin" "904 1024 -248" "classname" "monster_army" } { "light" "100" "style" "10" "classname" "light" "origin" "688 0 80" } { "message" "Shoot this secret door..." "spawnflags" "1" "angle" "0" "classname" "func_door_secret" "model" "*43" } { "origin" "672 -40 48" "classname" "item_shells" } { "classname" "trigger_secret" "model" "*44" } { "classname" "trigger_secret" "model" "*45" } { "classname" "trigger_secret" "model" "*46" } { "classname" "trigger_secret" "model" "*47" } { "classname" "trigger_secret" "model" "*48" } { "classname" "trigger_secret" "model" "*49" } { "light" "100" "origin" "0 632 -88" "classname" "light" } { "classname" "item_health" "origin" "600 2200 -128" "spawnflags" "1" } { "light" "220" "classname" "light" "origin" "832 1880 -504" } { "origin" "72 2056 -208" "classname" "misc_explobox" } { "light" "200" "origin" "-128 584 72" "classname" "light" } { "light" "200" "origin" "-128 568 -136" "classname" "light" } { "light" "100" "origin" "-56 632 -168" "classname" "light" } { "light" "200" "origin" "-56 864 -136" "classname" "light" } { "light" "200" "origin" "40 1672 -40" "classname" "light" } { "classname" "light" "origin" "216 1672 -40" "light" "200" } { "classname" "light" "origin" "128 1080 -152" "light" "200" } { "light" "200" "origin" "128 1096 72" "classname" "light" } { "light" "250" "classname" "light" "origin" "-352 1656 72" } { "origin" "608 1640 72" "classname" "light" "light" "250" } { "origin" "-48 1144 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "-48 1256 -320" } { "origin" "320 1256 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "312 1128 -320" } { "origin" "136 1128 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "136 1272 -320" } { "spawnflags" "3072" "wait" "5" "sounds" "2" "message" "You can jump across..." "classname" "trigger_multiple" "targetname" "t32" "model" "*50" } { "spawnflags" "3072" "wait" "5" "message" "You can jump up here..." "sounds" "2" "classname" "trigger_multiple" "targetname" "t31" "model" "*51" } { "light" "150" "origin" "1008 2128 -408" "classname" "light" } { "light" "250" "origin" "1312 544 -184" "classname" "light" } { "light" "200" "classname" "light" "origin" "1208 456 -184" } { "origin" "1416 456 -184" "classname" "light" "light" "200" } { "light" "170" "origin" "1312 728 -56" "classname" "light" } { "map" "e1m2" "classname" "trigger_changelevel" "model" "*52" } { "classname" "item_health" "origin" "1224 2464 -304" "spawnflags" "1" } { "classname" "light" "origin" "688 1680 -160" "light" "160" } { "light" "160" "origin" "-392 1688 -160" "classname" "light" } { "spawnflags" "768" "angle" "270" "origin" "288 1536 -200" "classname" "monster_army" } { "spawnflags" "768" "origin" "968 2432 -112" "classname" "monster_army" } { "wait" "5" "message" "Walk into the slipgate to exit." "classname" "trigger_multiple" "sounds" "2" "angle" "270" "model" "*53" } { "classname" "trigger_once" "killtarget" "t31" "target" "t31" "spawnflags" "3072" "model" "*54" } { "classname" "trigger_once" "spawnflags" "3072" "target" "t32" "killtarget" "t32" "model" "*55" } { "classname" "item_armor2" "origin" "1312 1048 -432" } { "classname" "ambient_comp_hum" "origin" "250 194 72" } { "origin" "714 194 72" "classname" "ambient_comp_hum" } { "classname" "ambient_comp_hum" "origin" "626 2058 -104" } { "origin" "466 2226 -104" "classname" "ambient_comp_hum" } { "classname" "info_intermission" "origin" "-112 704 56" "mangle" "20 45 0" } { "classname" "info_intermission" "origin" "-208 2736 192" "mangle" "20 225 0" } { "classname" "info_intermission" "origin" "240 2664 104" "mangle" "20 120 0" } { "classname" "info_intermission" "origin" "1376 1936 64" "mangle" "20 135 0" } { "angle" "90" "origin" "528 -296 72" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "432 -296 72" "angle" "90" } { "angle" "90" "origin" "480 -240 72" "classname" "info_player_coop" } { "classname" "func_wall" "spawnflags" "1792" "model" "*56" } { "classname" "func_wall" "spawnflags" "1792" "model" "*57" } { "classname" "ambient_drone" "origin" "1314 450 -200" } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e2m2.ent.orig����������������������������������������������������0000644�0000000�0000000�00000064572�12425501423�020012� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "message" "the Ogre Citadel" "sounds" "8" "wad" "gfx/wizard.wad" "classname" "worldspawn" "worldtype" "0" } { "origin" "160 -160 120" "classname" "light" } { "angle" "90" "origin" "-256 -1952 280" "classname" "info_player_start" } { "classname" "light" "origin" "160 -392 248" "light" "200" } { "classname" "light" "origin" "160 -648 184" } { "classname" "light" "origin" "-56 -392 248" "light" "200" } { "classname" "light" "origin" "376 -392 248" "light" "200" } { "classname" "light" "origin" "288 -416 -72" "light" "200" } { "classname" "light" "origin" "32 -416 -72" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "10 -270 148" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "314 -270 148" "light" "250" } { "classname" "light" "origin" "-264 -440 248" "light" "200" } { "classname" "light" "origin" "584 -440 248" "light" "200" } { "classname" "light" "origin" "544 -648 248" } { "light" "150" "origin" "648 -456 -184" "classname" "light" } { "origin" "376 -800 184" "classname" "light" } { "classname" "light" "origin" "-152 -752 184" "light" "250" } { "classname" "light" "origin" "-232 -592 184" "light" "250" } { "classname" "light" "origin" "160 112 184" } { "classname" "light" "origin" "160 352 120" } { "classname" "light" "origin" "160 216 -48" "light" "120" } { "classname" "light" "origin" "160 16 -48" "light" "120" } { "classname" "light" "origin" "160 544 144" "light" "225" } { "classname" "light" "origin" "480 576 88" } { "classname" "light" "origin" "480 448 88" } { "classname" "light" "origin" "480 576 168" "light" "250" } { "classname" "light" "origin" "480 448 168" "light" "250" } { "classname" "light" "origin" "160 896 312" "light" "350" } { "classname" "light" "origin" "288 896 312" "light" "100" } { "classname" "light" "origin" "32 896 312" "light" "100" } { "classname" "light" "origin" "160 1008 312" "light" "100" } { "classname" "light" "origin" "160 784 312" "light" "100" } { "classname" "light" "origin" "392 120 184" "light" "350" } { "classname" "light" "origin" "568 208 184" "light" "350" } { "classname" "light" "origin" "720 480 184" } { "classname" "light" "origin" "640 632 184" } { "classname" "light" "origin" "472 1152 56" } { "classname" "light" "origin" "512 896 152" } { "origin" "800 800 184" "classname" "light" } { "light" "200" "origin" "632 1264 -40" "classname" "light" } { "origin" "800 1032 184" "classname" "light" } { "origin" "760 1472 64" "classname" "light" } { "light" "200" "origin" "544 1416 56" "classname" "light" } { "origin" "672 1256 184" "classname" "light" "light" "200" } { "light" "200" "origin" "1024 1272 184" "classname" "light" } { "light" "200" "origin" "992 1440 184" "classname" "light" } { "origin" "1240 488 184" "classname" "light" } { "origin" "1280 136 176" "classname" "light" } { "origin" "160 1304 136" "classname" "light" } { "origin" "160 1648 256" "classname" "light" "light" "200" } { "origin" "240 1600 256" "classname" "light" "light" "200" } { "origin" "16 1616 168" "classname" "light" "light" "200" } { "light" "200" "origin" "-120 1304 40" "classname" "light" } { "origin" "-352 1144 16" "classname" "light" "light" "250" } { "origin" "-56 1096 64" "classname" "light" } { "light" "200" "origin" "-56 1152 280" "classname" "light" } { "light" "350" "origin" "-440 1144 200" "classname" "light" } { "light" "200" "origin" "-352 1336 -72" "classname" "light" } { "origin" "-488 368 56" "classname" "light" "light" "250" } { "light" "350" "origin" "-488 896 136" "classname" "light" } { "origin" "-216 896 184" "classname" "light" "light" "250" } { "origin" "-128 536 168" "classname" "light" "light" "200" } { "light" "150" "origin" "-104 480 32" "classname" "light" } { "light" "150" "origin" "-208 936 56" "classname" "light" } { "light" "150" "origin" "-208 736 32" "classname" "light" } { "origin" "-344 64 184" "classname" "light" } { "light" "350" "origin" "-648 384 184" "classname" "light" } { "light" "350" "origin" "-488 688 184" "classname" "light" } { "light" "150" "origin" "-680 496 -36" "classname" "light" } { "light" "350" "origin" "-600 1104 96" "classname" "light" } { "origin" "-824 896 168" "classname" "light" } { "origin" "-896 600 160" "classname" "light" } { "target" "t1" "classname" "trigger_teleport" "model" "*1" } { "spawnflags" "1792" "targetname" "t1" "origin" "-448 264 -56" "classname" "info_teleport_destination" "angle" "45" } { "light" "250" "origin" "-168 1320 160" "classname" "light" } { "origin" "-24 896 184" "classname" "light" } { "origin" "-104 896 184" "classname" "light" "light" "250" } { "spawnflags" "2" "origin" "-680 880 48" "classname" "item_health" } { "angle" "90" "origin" "-896 512 24" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "-184 560 128" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "160 1640 160" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "1272 112 80" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "176 -784 24" "classname" "info_player_deathmatch" } { "spawnflags" "1" "origin" "208 -160 0" "classname" "item_rockets" } { "origin" "64 464 0" "classname" "item_health" } { "origin" "120 464 0" "classname" "item_health" } { "spawnflags" "1" "origin" "-8 840 64" "classname" "item_health" } { "spawnflags" "1" "origin" "-8 952 64" "classname" "item_health" } { "spawnflags" "9" "origin" "568 880 0" "classname" "item_weapon" } { "origin" "456 1104 -88" "classname" "item_health" } { "spawnflags" "1" "origin" "664 1272 -88" "classname" "item_shells" } { "angle" "225" "origin" "888 1312 120" "classname" "info_player_deathmatch" } { "origin" "1328 168 56" "classname" "item_health" } { "origin" "1328 128 56" "classname" "item_health" } { "origin" "1328 208 56" "classname" "item_health" } { "spawnflags" "1" "origin" "816 1472 0" "classname" "item_shells" } { "light" "200" "origin" "-64 -120 -56" "classname" "light" } { "light" "200" "origin" "-296 -160 -56" "classname" "light" } { "light" "200" "origin" "-296 -208 -272" "classname" "light" } { "classname" "func_plat" "model" "*2" } { "spawnflags" "2" "origin" "-192 -176 -80" "classname" "item_health" } { "light" "350" "origin" "-816 128 184" "classname" "light" } { "light" "350" "origin" "-664 -80 184" "classname" "light" } { "light" "250" "origin" "-656 112 32" "classname" "light" } { "origin" "-352 208 56" "classname" "light" "light" "250" } { "origin" "-184 504 24" "classname" "light" "light" "250" } { "classname" "item_armor1" "origin" "400 -888 0" } { "spawnflags" "1792" "classname" "item_armorInv" "origin" "-104 448 104" } { "classname" "item_armor2" "origin" "-680 496 32" } { "classname" "weapon_grenadelauncher" "origin" "168 1608 136" "spawnflags" "1792" } { "classname" "weapon_rocketlauncher" "origin" "1232 176 56" "spawnflags" "1792" } { "classname" "weapon_supernailgun" "origin" "-960 944 40" "spawnflags" "1792" } { "classname" "weapon_supershotgun" "origin" "752 1464 0" "spawnflags" "1792" } { "classname" "weapon_nailgun" "origin" "160 120 24" "spawnflags" "1792" } { "classname" "item_rockets" "origin" "-224 792 104" "spawnflags" "1792" } { "classname" "item_rockets" "origin" "-640 120 -56" "spawnflags" "1792" } { "light" "200" "origin" "-70 -1126 212" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "186 -1134 148" } { "light" "200" "origin" "138 -966 100" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "-150 -1318 260" } { "light" "150" "origin" "184 -880 72" "classname" "light" } { "style" "6" "light" "200" "origin" "-46 -1742 340" "classname" "light_torch_small_walltorch" } { "style" "1" "light" "200" "classname" "light_torch_small_walltorch" "origin" "-486 -1726 340" } { "origin" "-272 -1544 384" "classname" "light" "light" "200" } { "style" "6" "light" "200" "classname" "light_torch_small_walltorch" "origin" "-414 -2006 340" } { "style" "1" "light" "200" "origin" "-134 -1958 340" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "-472 -1840 328" "classname" "light" } { "classname" "light" "origin" "-72 -1592 328" "light" "150" } { "light" "150" "origin" "-320 -1424 264" "classname" "light" } { "light" "150" "origin" "-256 -1952 280" "classname" "light" } { "light" "200" "classname" "light" "origin" "-272 -1720 312" } { "origin" "-232 -1280 168" "classname" "path_corner" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "-64 -1176 120" "targetname" "t6" "target" "t7" } { "origin" "152 -1104 56" "classname" "path_corner" "targetname" "t7" "target" "t8" } { "classname" "path_corner" "origin" "192 -952 8" "targetname" "t8" "target" "t9" } { "origin" "184 -808 8" "classname" "path_corner" "target" "t3" "targetname" "t9" } { "classname" "path_corner" "origin" "512 -776 8" "targetname" "t3" "target" "t10" } { "origin" "-200 -648 8" "classname" "path_corner" "targetname" "t4" "target" "t11" } { "classname" "monster_knight" "origin" "-360 -1616 232" "target" "t5" "angle" "90" } { "origin" "512 -648 8" "classname" "path_corner" "targetname" "t10" "target" "t4" } { "classname" "path_corner" "origin" "-200 -776 8" "targetname" "t11" "target" "t3" } { "classname" "monster_knight" "origin" "24 -632 24" "spawnflags" "256" "target" "t4" } { "classname" "monster_knight" "origin" "336 -752 24" "spawnflags" "256" "target" "t3" } { "classname" "monster_knight" "origin" "56 -712 24" "angle" "270" "spawnflags" "768" } { "spawnflags" "768" "angle" "270" "origin" "160 -712 24" "classname" "monster_knight" } { "classname" "monster_knight" "origin" "264 -712 24" "angle" "270" "spawnflags" "768" } { "classname" "item_health" "origin" "-432 -1640 208" "spawnflags" "1" } { "classname" "item_shells" "origin" "-352 -592 0" } { "classname" "func_door" "angle" "90" "spawnflags" "1" "targetname" "t13" "wait" "-1" "sounds" "3" "dmg" "100" "model" "*3" } { "health" "1" "angle" "90" "classname" "func_button" "target" "t12" "wait" "-1" "sounds" "1" "model" "*4" } { "classname" "func_button" "angle" "90" "health" "1" "target" "t12" "wait" "-1" "sounds" "1" "model" "*5" } { "classname" "trigger_counter" "targetname" "t12" "count" "2" "target" "t13" "model" "*6" } { "classname" "monster_demon1" "origin" "160 -128 24" "angle" "270" "targetname" "t12" } { "classname" "light" "origin" "-8 -288 64" "light" "200" } { "light" "200" "origin" "328 -288 64" "classname" "light" } { "light" "200" "origin" "-296 -448 -248" "classname" "light" } { "classname" "light" "origin" "160 -368 -248" "light" "200" } { "light" "200" "origin" "616 -448 -248" "classname" "light" } { "classname" "light" "origin" "408 -456 -248" "light" "200" } { "light" "200" "origin" "-40 -424 -248" "classname" "light" } { "classname" "light" "origin" "-280 -448 32" "light" "200" } { "light" "200" "origin" "632 -424 32" "classname" "light" } { "classname" "light" "origin" "160 -480 8" "light" "150" } { "classname" "func_door" "angle" "180" "targetname" "t12" "sounds" "3" "speed" "200" "wait" "-1" "lip" "-2" "model" "*7" } { "classname" "func_door" "angle" "0" "speed" "200" "wait" "-1" "lip" "-2" "model" "*8" } { "classname" "light" "origin" "160 -304 112" "light" "170" } { "classname" "light" "origin" "160 640 104" "light" "200" } { "classname" "func_door" "angle" "-1" "targetname" "t14" "sounds" "1" "model" "*9" } { "classname" "trigger_multiple" "target" "t14" "wait" "10" "model" "*10" } { "targetname" "t28" "classname" "func_door" "angle" "-1" "wait" "-1" "sounds" "1" "speed" "200" "spawnflags" "2048" "model" "*11" } { "angle" "270" "classname" "func_button" "target" "t15" "wait" "-1" "lip" "2" "sounds" "1" "spawnflags" "2048" "model" "*12" } { "classname" "light" "origin" "-296 432 0" "light" "200" } { "light" "200" "origin" "-312 416 152" "classname" "light" } { "classname" "light" "origin" "-184 320 146" "light" "200" } { "classname" "item_key2" "origin" "-552 192 -40" "sounds" "1" "spawnflags" "2048" } { "classname" "item_spikes" "origin" "-680 88 -48" } { "classname" "func_door" "angle" "-2" "spawnflags" "33" "speed" "10" "sounds" "3" "wait" "-1" "targetname" "t16" "dmg" "100" "model" "*13" } { "sounds" "3" "classname" "func_door" "angle" "90" "spawnflags" "2056" "wait" "-1" "model" "*14" } { "spawnflags" "2056" "angle" "270" "classname" "func_door" "wait" "-1" "model" "*15" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t16" "lip" "12" "model" "*16" } { "classname" "light" "origin" "888 1080 -104" "light" "160" } { "light" "160" "origin" "888 888 -104" "classname" "light" } { "classname" "light" "origin" "880 696 -104" "light" "160" } { "light" "160" "origin" "696 888 -104" "classname" "light" } { "classname" "light" "origin" "696 1080 -104" "light" "160" } { "light" "200" "origin" "696 672 -104" "classname" "light" } { "classname" "light" "origin" "568 512 -104" "light" "200" } { "light" "160" "origin" "840 504 -104" "classname" "light" } { "classname" "light" "origin" "832 328 -104" "light" "160" } { "classname" "light" "origin" "936 512 96" "light" "200" } { "classname" "light" "origin" "-248 1080 56" "light" "150" } { "classname" "light" "origin" "888 1264 176" "light" "170" } { "classname" "func_door" "angle" "-2" "targetname" "t17" "sounds" "1" "model" "*17" } { "classname" "trigger_multiple" "target" "t17" "wait" "5" "model" "*18" } { "classname" "light" "origin" "160 120 -24" "light" "160" } { "spawnflags" "256" "classname" "trigger_multiple" "target" "t18" "targetname" "t23" "model" "*19" } { "wait" "0.5" "classname" "trap_spikeshooter" "origin" "88 368 40" "angle" "0" "targetname" "t18" } { "classname" "func_wall" "spawnflags" "2048" "model" "*20" } { "classname" "monster_demon1" "origin" "-160 608 128" "targetname" "t19" } { "classname" "trigger_once" "target" "t19" "model" "*21" } { "classname" "light" "origin" "-528 512 -104" "light" "200" } { "light" "200" "origin" "-344 592 -104" "classname" "light" } { "classname" "light" "origin" "-336 760 -104" "light" "200" } { "light" "200" "origin" "-432 856 -104" "classname" "light" } { "classname" "monster_ogre" "origin" "-416 440 -40" "spawnflags" "1536" "target" "t20" } { "classname" "monster_shambler" "origin" "-272 296 -40" "spawnflags" "256" "target" "t20" } { "classname" "path_corner" "origin" "-328 272 -56" "targetname" "t20" "target" "t21" } { "origin" "-400 480 -56" "classname" "path_corner" "target" "t20" "targetname" "t21" } { "classname" "item_health" "origin" "-600 144 -64" } { "classname" "weapon_supershotgun" "origin" "440 512 0" "spawnflags" "2048" } { "classname" "light" "origin" "-120 176 184" "light" "250" } { "origin" "-96 0 184" "classname" "light" "light" "200" } { "classname" "light" "origin" "312 116 -48" "light" "200" } { "classname" "path_corner" "origin" "8 112 32" "target" "t25" "targetname" "t24" } { "origin" "312 112 32" "classname" "path_corner" "targetname" "t25" "target" "t24" } { "classname" "monster_ogre" "origin" "112 112 48" "target" "t24" "spawnflags" "256" } { "classname" "item_shells" "origin" "88 -160 0" "spawnflags" "1" } { "light" "250" "classname" "light" "origin" "-352 144 56" } { "classname" "monster_demon1" "origin" "-80 -440 -296" "spawnflags" "256" "target" "t26" } { "classname" "path_corner" "origin" "-216 -456 -312" "targetname" "t26" "target" "t27" } { "origin" "536 -448 -312" "classname" "path_corner" "target" "t26" "targetname" "t27" } { "light" "200" "origin" "320 232 -104" "classname" "light" } { "classname" "light" "origin" "312 0 -104" "light" "200" } { "light" "160" "origin" "-8 0 -104" "classname" "light" } { "classname" "light" "origin" "-8 232 -104" "light" "200" } { "light" "200" "origin" "-16 112 -104" "classname" "light" } { "classname" "light" "origin" "-248 -8 -104" "light" "200" } { "light" "200" "origin" "-472 120 -104" "classname" "light" } { "wait" "-1" "classname" "func_door" "angle" "-1" "targetname" "t15" "sounds" "1" "spawnflags" "2048" "model" "*22" } { "classname" "func_door" "angle" "-2" "spawnflags" "2081" "targetname" "t28" "wait" "10" "speed" "200" "sounds" "1" "model" "*23" } { "classname" "trigger_once" "target" "t28" "model" "*24" } { "classname" "trigger_once" "target" "t12" "model" "*25" } { "classname" "monster_ogre" "origin" "160 1432 128" "angle" "270" } { "classname" "monster_ogre" "origin" "-216 784 128" "angle" "90" } { "classname" "info_teleport_destination" "origin" "-360 888 24" "spawnflags" "2048" "targetname" "t1" } { "classname" "monster_zombie" "origin" "-288 -232 -296" "angle" "270" } { "classname" "monster_zombie" "origin" "168 -8 -104" "angle" "90" } { "classname" "monster_ogre" "origin" "648 1232 -64" "angle" "180" } { "sounds" "1" "classname" "func_door" "angle" "-2" "targetname" "t29" "model" "*26" } { "classname" "monster_ogre" "origin" "520 752 24" "angle" "90" "spawnflags" "256" "targetname" "t29" } { "classname" "trigger_once" "target" "t29" "model" "*27" } { "classname" "weapon_nailgun" "origin" "152 1608 136" "spawnflags" "2048" } { "classname" "path_corner" "origin" "544 896 8" "targetname" "t30" "target" "t31" } { "origin" "56 896 72" "classname" "path_corner" "target" "t30" "targetname" "t31" } { "classname" "path_corner" "origin" "168 552 8" "targetname" "t32" "target" "t33" } { "origin" "168 1392 8" "classname" "path_corner" "target" "t32" "targetname" "t33" } { "classname" "monster_knight" "origin" "240 584 24" "target" "t32" } { "classname" "monster_knight" "origin" "504 960 24" "target" "t30" "spawnflags" "256" } { "classname" "monster_knight" "origin" "-16 896 88" "angle" "0" } { "classname" "monster_knight" "origin" "256 1224 24" "angle" "225" "spawnflags" "256" } { "target" "t49" "origin" "-24 1064 16" "classname" "monster_ogre" } { "spawnflags" "256" "angle" "45" "origin" "-184 1080 128" "classname" "monster_ogre" } { "angle" "45" "origin" "-256 1216 128" "classname" "monster_knight" } { "targetname" "t16" "angle" "270" "origin" "784 520 56" "classname" "monster_demon1" } { "classname" "path_corner" "origin" "-352 888 16" "targetname" "t34" "target" "t35" } { "origin" "-120 888 8" "classname" "path_corner" "target" "t34" "targetname" "t35" } { "classname" "monster_ogre" "origin" "-184 912 24" "target" "t34" "spawnflags" "256" } { "classname" "monster_ogre" "origin" "-720 896 64" } { "classname" "monster_knight" "origin" "-344 760 24" "angle" "135" "spawnflags" "256" } { "classname" "monster_knight" "origin" "-392 584 24" "angle" "90" "spawnflags" "256" } { "angle" "90" "classname" "monster_knight" "origin" "-528 528 24" "spawnflags" "768" } { "targetname" "t37" "target" "t36" "origin" "-896 968 48" "classname" "path_corner" } { "target" "t37" "targetname" "t36" "classname" "path_corner" "origin" "-896 568 48" } { "spawnflags" "256" "target" "t36" "origin" "-840 600 24" "classname" "monster_ogre" } { "style" "32" "targetname" "t15" "light" "200" "origin" "-56 304 152" "classname" "light" } { "dmg" "100" "speed" "200" "targetname" "t15" "target" "t38" "classname" "func_train" "model" "*28" } { "target" "t39" "targetname" "t40" "origin" "-216 280 104" "classname" "path_corner" } { "target" "t40" "targetname" "t38" "classname" "path_corner" "origin" "-16 280 104" } { "target" "t38" "wait" "-1" "targetname" "t39" "origin" "-16 280 104" "classname" "path_corner" } { "angle" "180" "origin" "680 1472 24" "classname" "monster_ogre" "spawnflags" "256" } { "spawnflags" "256" "angle" "180" "origin" "864 1448 24" "classname" "monster_knight" } { "target" "t42" "targetname" "t41" "origin" "1024 1264 104" "classname" "path_corner" } { "targetname" "t42" "target" "t41" "classname" "path_corner" "origin" "704 1264 104" } { "target" "t41" "origin" "1056 1320 120" "classname" "monster_knight" } { "spawnflags" "257" "origin" "552 1280 128" "classname" "monster_knight" } { "spawnflags" "1" "origin" "432 1280 128" "classname" "monster_knight" } { "spawnflags" "2048" "angle" "0" "wait" "-1" "sounds" "0" "health" "1" "target" "t28" "classname" "func_button" "model" "*29" } { "origin" "-72 296 104" "classname" "item_health" } { "classname" "item_health" "origin" "-64 504 104" } { "origin" "-312 192 -64" "classname" "item_health" } { "spawnflags" "1" "origin" "-80 384 -64" "classname" "item_spikes" } { "origin" "-224 976 104" "classname" "item_shells" } { "target" "t666" "classname" "trigger_multiple" "wait" "10" "model" "*30" } { "target" "t45" "targetname" "t44" "origin" "984 568 8" "classname" "path_corner" } { "target" "t46" "targetname" "t45" "classname" "path_corner" "origin" "976 464 8" } { "target" "t47" "targetname" "t46" "origin" "1224 448 40" "classname" "path_corner" } { "target" "t44" "targetname" "t43" "classname" "path_corner" "origin" "1272 520 40" } { "target" "t48" "targetname" "t47" "classname" "path_corner" "origin" "1224 144 64" } { "targetname" "t48" "target" "t43" "origin" "1344 120 64" "classname" "path_corner" } { "target" "t45" "origin" "968 520 24" "classname" "monster_ogre" } { "spawnflags" "256" "target" "t43" "origin" "1312 328 80" "classname" "monster_knight" } { "spawnflags" "768" "target" "t47" "origin" "1240 296 80" "classname" "monster_ogre" } { "origin" "-360 1064 -8" "classname" "weapon_grenadelauncher" } { "target" "t50" "targetname" "t49" "origin" "-16 1168 0" "classname" "path_corner" } { "targetname" "t50" "target" "t49" "classname" "path_corner" "origin" "-232 1168 0" } { "origin" "1448 -128 -56" "classname" "light" } { "wait" "-1" "classname" "func_door" "angle" "270" "model" "*31" } { "wait" "-1" "targetname" "t52" "sounds" "3" "classname" "func_door" "angle" "90" "model" "*32" } { "classname" "light" "origin" "1984 -184 288" "light" "350" } { "classname" "light" "origin" "1760 -312 -184" "light" "200" } { "origin" "1832 -64 -184" "classname" "light" "light" "200" } { "light" "160" "origin" "1808 -296 -24" "classname" "light" } { "classname" "light" "origin" "1224 -8 -184" "light" "160" } { "light" "160" "origin" "1240 -208 -184" "classname" "light" } { "classname" "light" "origin" "1680 -104 -184" "light" "160" } { "light" "160" "origin" "1584 -304 -184" "classname" "light" } { "origin" "1592 -72 288" "classname" "light" } { "classname" "light" "origin" "1328 -232 288" } { "classname" "light" "origin" "1280 -16 327" "light" "250" } { "classname" "light" "origin" "1792 -152 88" "light" "160" } { "light" "160" "origin" "1632 -296 88" "classname" "light" } { "origin" "1696 -280 288" "classname" "light" } { "classname" "light" "origin" "1240 -224 -8" "light" "200" } { "classname" "func_wall" "spawnflags" "3072" "model" "*33" } { "classname" "func_wall" "spawnflags" "3072" "model" "*34" } { "classname" "func_wall" "spawnflags" "3072" "model" "*35" } { "classname" "func_wall" "spawnflags" "3072" "model" "*36" } { "classname" "func_wall" "spawnflags" "3072" "model" "*37" } { "classname" "monster_ogre" "origin" "1992 -192 200" "angle" "180" "spawnflags" "256" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "targetname" "t51" "model" "*38" } { "classname" "trigger_multiple" "target" "t51" "model" "*39" } { "classname" "func_plat" "model" "*40" } { "classname" "light" "origin" "1480 56 -168" "light" "160" } { "origin" "1432 280 -64" "classname" "light" "light" "160" } { "light" "160" "classname" "light" "origin" "1424 280 96" } { "light" "160" "origin" "1472 232 -168" "classname" "light" } { "classname" "monster_zombie" "origin" "1592 -24 160" "angle" "180" } { "classname" "monster_zombie" "origin" "1432 -304 112" "angle" "135" "spawnflags" "256" } { "classname" "monster_zombie" "origin" "1304 -288 112" "angle" "90" "spawnflags" "256" } { "classname" "monster_zombie" "origin" "1576 -216 136" "angle" "180" "spawnflags" "768" } { "classname" "monster_zombie" "origin" "1928 -80 200" "spawnflags" "768" "angle" "180" } { "angle" "180" "spawnflags" "768" "origin" "1928 -280 200" "classname" "monster_zombie" } { "classname" "trigger_changelevel" "map" "e2m3" "model" "*41" } { "classname" "light" "origin" "80 1544 40" "light" "160" } { "light" "160" "origin" "-112 1544 40" "classname" "light" } { "classname" "item_shells" "origin" "1056 552 8" } { "classname" "light" "origin" "-112 1672 40" "light" "160" } { "light" "160" "origin" "88 1680 40" "classname" "light" } { "classname" "item_health" "origin" "-168 1688 -8" "spawnflags" "1" } { "classname" "monster_knight" "origin" "-112 1616 16" "angle" "45" "spawnflags" "768" } { "classname" "monster_demon1" "origin" "1760 -208 -216" "angle" "180" } { "classname" "trigger_secret" "model" "*42" } { "classname" "trigger_secret" "model" "*43" } { "classname" "trigger_secret" "model" "*44" } { "classname" "trigger_multiple" "target" "t29" "model" "*45" } { "classname" "item_shells" "origin" "-144 -1728 288" "spawnflags" "768" } { "classname" "item_rockets" "origin" "2000 -304 176" "spawnflags" "1793" } { "classname" "item_rockets" "origin" "2000 -112 176" "spawnflags" "1793" } { "origin" "-62 -702 72" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "386 -702 72" } { "origin" "-246 -470 -264" "classname" "ambient_swamp2" } { "classname" "ambient_swamp1" "origin" "554 -454 -264" } { "origin" "162 -430 -264" "classname" "ambient_swamp1" } { "spawnflags" "1" "origin" "-72 576 104" "classname" "item_shells" } { "spawnflags" "2048" "wait" "10" "target" "t16" "classname" "trigger_multiple" "model" "*46" } { "targetname" "t16" "sounds" "4" "wait" "-1" "angle" "-1" "classname" "func_door" "model" "*47" } { "origin" "-184 1480 168" "classname" "light" "light" "160" } { "classname" "light" "origin" "-224 1592 168" "light" "100" } { "target" "t52" "classname" "trigger_once" "model" "*48" } { "mangle" "20 30 0" "origin" "1224 -288 336" "classname" "info_intermission" } { "mangle" "20 180 0" "origin" "-352 760 240" "classname" "info_intermission" } { "mangle" "20 135 0" "origin" "480 -440 208" "classname" "info_intermission" } { "angle" "90" "origin" "-176 -1904 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-128 -1848 264" "angle" "90" } { "angle" "90" "origin" "-192 -1808 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-320 -1824 264" "angle" "90" } { "spawnflags" "1792" "classname" "func_wall" "model" "*49" } { "spawnflags" "1792" "origin" "200 -664 0" "classname" "weapon_lightning" } { "origin" "-184 1512 144" "classname" "item_artifact_super_damage" } { "classname" "item_cells" "origin" "240 -664 0" "spawnflags" "1793" } { "classname" "item_cells" "origin" "392 640 0" "spawnflags" "1793" } { "classname" "item_cells" "origin" "-168 456 104" "spawnflags" "1793" } { "classname" "func_door" "angle" "-1" "spawnflags" "1" "wait" "6" "speed" "1000" "sounds" "3" "targetname" "t15" "model" "*50" } { "classname" "weapon_grenadelauncher" "origin" "1312 280 56" "spawnflags" "3584" } { "sounds" "2" "wait" "5" "message" "Shoot the buttons..." "spawnflags" "3584" "classname" "trigger_multiple" "targetname" "t53" "model" "*51" } { "classname" "trigger_relay" "origin" "-72 -320 48" "targetname" "t13" "killtarget" "t53" } ��������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e2m7.ent.orig����������������������������������������������������0000644�0000000�0000000�00000142506�12403131422�020003� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "wad" "gfx/tim.wad" "classname" "worldspawn" "sounds" "7" "worldtype" "0" "message" "the Underearth" } { "angle" "90" "origin" "1136 -1100 -72" "classname" "info_player_start" } { "origin" "1184 -776 -152" "classname" "light" "light" "150" } { "classname" "light" "origin" "1704 -584 -184" "light" "150" } { "classname" "light" "origin" "1640 -688 -184" "light" "150" } { "classname" "light" "origin" "1696 -888 -192" "light" "150" } { "classname" "light" "origin" "1088 -960 -152" "light" "150" } { "classname" "light" "origin" "1248 -960 -152" "light" "150" } { "classname" "light" "origin" "1016 -768 -152" "light" "100" } { "classname" "light" "origin" "896 -920 -152" "light" "150" } { "light" "100" "origin" "1584 -208 -112" "classname" "light" } { "light" "100" "origin" "1776 -208 -112" "classname" "light" } { "light" "150" "origin" "1584 -88 -112" "classname" "light" } { "origin" "1774 58 -76" "classname" "light_torch_small_walltorch" } { "light" "100" "origin" "1584 -488 -232" "classname" "light" } { "light" "100" "origin" "1768 -480 -232" "classname" "light" } { "light" "150" "origin" "1752 -112 -176" "classname" "light" } { "light" "150" "origin" "1592 -120 -176" "classname" "light" } { "light" "150" "origin" "1592 -248 -192" "classname" "light" } { "light" "200" "origin" "1768 -240 -192" "classname" "light" } { "light" "150" "origin" "1676 -220 -188" "classname" "light" } { "light" "150" "origin" "1672 -40 -136" "classname" "light" } { "light" "150" "origin" "1676 -376 -252" "classname" "light" } { "light" "250" "origin" "1112 952 -92" "classname" "light" } { "light" "200" "origin" "1280 928 -152" "classname" "light" } { "classname" "light" "origin" "704 952 -92" "light" "250" } { "classname" "light" "origin" "824 1112 -92" "light" "200" } { "classname" "light" "origin" "952 760 -92" "light" "200" } { "classname" "light" "origin" "824 760 -92" "light" "200" } { "light" "250" "origin" "952 1112 -92" "classname" "light" } { "classname" "light" "origin" "1128 -848 288" "light" "500" } { "classname" "light" "origin" "1144 -432 288" } { "classname" "light" "origin" "864 -552 272" "light" "200" } { "classname" "light" "origin" "1392 -568 168" "light" "200" } { "classname" "light" "origin" "1416 -592 -24" "light" "150" } { "classname" "light" "origin" "888 -584 -24" "light" "150" } { "classname" "light_torch_small_walltorch" "origin" "1058 -466 -24" "light" "225" } { "origin" "1214 -466 -24" "classname" "light_torch_small_walltorch" "light" "225" } { "classname" "light_torch_small_walltorch" "origin" "1198 -66 40" "light" "300" } { "classname" "light" "origin" "1144 -204 172" "light" "150" } { "classname" "light" "origin" "1144 -292 -32" "light" "150" } { "classname" "item_spikes" "origin" "880 -592 -96" "spawnflags" "1" } { "classname" "item_health" "origin" "1068 -944 -96" } { "classname" "light" "origin" "1128 -1084 96" "light" "300" } { "classname" "light" "origin" "888 -848 248" "light" "150" } { "light" "150" "origin" "1504 -896 248" "classname" "light" } { "classname" "light" "origin" "1304 -1048 24" "light" "225" } { "classname" "light" "origin" "1520 -872 -192" "light" "150" } { "light" "100" "origin" "1384 -776 -184" "classname" "light" } { "classname" "light" "origin" "1368 -912 -184" "light" "100" } { "classname" "light" "origin" "1584 496 148" "light" "200" } { "light" "200" "origin" "1488 496 148" "classname" "light" } { "classname" "light" "origin" "1688 164 148" "light" "200" } { "light" "200" "origin" "1352 496 148" "classname" "light" } { "classname" "light" "origin" "1608 496 -36" "light" "200" } { "light" "200" "origin" "1456 496 -36" "classname" "light" } { "classname" "light" "origin" "1692 600 -12" "light" "200" } { "light" "200" "origin" "1274 618 -64" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1274 378 -64" "light" "200" } { "classname" "light" "origin" "1256 496 -40" "light" "200" } { "spawnflags" "2056" "wait" "-1" "classname" "func_door" "angle" "270" "model" "*1" } { "wait" "-1" "spawnflags" "2056" "sounds" "3" "angle" "90" "classname" "func_door" "model" "*2" } { "light" "200" "origin" "1968 1792 -257" "classname" "light" } { "light" "250" "origin" "1880 1792 -105" "classname" "light" } { "classname" "light" "origin" "1976 1944 56" "light" "150" } { "light" "150" "origin" "1992 1624 64" "classname" "light" } { "classname" "light" "origin" "1944 1736 64" "light" "150" } { "light" "150" "origin" "1944 1832 64" "classname" "light" } { "classname" "light" "origin" "1128 496 -24" "light" "250" } { "light" "150" "origin" "1120 632 -24" "classname" "light" } { "light" "200" "origin" "928 544 -24" "classname" "light" } { "classname" "light" "origin" "640 664 -8" "light" "200" } { "light" "200" "origin" "848 672 -8" "classname" "light" } { "classname" "light" "origin" "1024 544 -188" "light" "175" } { "light" "250" "origin" "64 192 136" "classname" "light" } { "classname" "light" "origin" "528 184 136" "light" "250" } { "light" "200" "origin" "72 408 8" "classname" "light" } { "classname" "light" "origin" "80 -48 8" "light" "200" } { "light" "250" "origin" "400 384 80" "classname" "light" } { "classname" "light" "origin" "392 -16 80" "light" "250" } { "classname" "light" "origin" "312 184 -80" "light" "200" } { "light" "200" "origin" "440 184 -80" "classname" "light" } { "classname" "light" "origin" "504 368 -120" "light" "250" } { "light" "150" "origin" "632 192 -120" "classname" "light" } { "classname" "light" "origin" "504 -16 -120" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "774 446 -172" "light" "250" } { "origin" "774 -70 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "light" "250" "origin" "896 -128 152" "classname" "light" } { "classname" "light" "origin" "896 184 152" "light" "250" } { "light" "150" "origin" "656 184 216" "classname" "light" } { "classname" "light" "origin" "304 368 -152" "light" "200" } { "light" "200" "origin" "0 480 -168" "classname" "light" } { "classname" "light" "origin" "96 376 -168" "light" "200" } { "classname" "light" "origin" "16 1480 -96" "light" "200" } { "light" "200" "origin" "1280 1824 -120" "classname" "light" } { "light" "200" "origin" "504 1816 -120" "classname" "light" } { "classname" "light" "origin" "712 1808 -120" "light" "200" } { "light" "200" "origin" "1064 1808 -120" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "858 1950 -172" "light" "250" } { "origin" "658 1950 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "666 1682 -172" "light" "250" } { "origin" "858 1682 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "classname" "light" "origin" "1248 1384 -32" "light" "200" } { "classname" "light" "origin" "1688 936 -136" "light" "200" } { "light" "250" "origin" "1856 1444 -52" "classname" "light" } { "light" "150" "origin" "1864 1316 -192" "classname" "light" } { "classname" "light" "origin" "1776 1212 -192" "light" "150" } { "light" "150" "origin" "1696 1076 -192" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "1770 730 -64" "light" "250" } { "classname" "light" "origin" "1760 1720 -201" "light" "250" } { "classname" "light" "origin" "1632 1520 -201" "light" "200" } { "classname" "light" "origin" "1984 1504 -201" "light" "200" } { "light" "250" "classname" "light_torch_small_walltorch" "origin" "1874 2104 -300" } { "light" "250" "origin" "1712 2104 -300" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light" "origin" "1792 2048 48" } { "classname" "light_flame_large_yellow" "origin" "1362 1778 0" } { "classname" "light" "origin" "1408 1776 -124" "light" "200" } { "classname" "light" "origin" "1520 1880 -84" "light" "175" } { "light" "175" "origin" "1416 1512 -84" "classname" "light" } { "classname" "light" "origin" "1376 1568 -164" "light" "150" } { "light" "150" "origin" "1416 1888 -164" "classname" "light" } { "classname" "light" "origin" "1544 2072 -164" "light" "150" } { "classname" "light" "origin" "1552 1968 36" "light" "250" } { "classname" "light" "origin" "1416 1968 -16" "light" "175" } { "light" "175" "origin" "1416 2176 -16" "classname" "light" } { "classname" "light" "origin" "1240 2176 -16" "light" "175" } { "light" "175" "origin" "1240 2000 -16" "classname" "light" } { "classname" "light" "origin" "1264 1576 -72" "light" "200" } { "light" "200" "origin" "992 1480 -40" "classname" "light" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "968 1632 -132" } { "light" "200" "origin" "968 1328 -132" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1474 2234 -133" "light" "200" } { "origin" "1182 2234 -133" "classname" "light_torch_small_walltorch" "light" "200" } { "classname" "light" "origin" "1936 1480 48" "light" "150" } { "light" "150" "origin" "1544 1528 64" "classname" "light" } { "classname" "light" "origin" "1472 1488 24" "light" "150" } { "classname" "light" "origin" "1400 1664 96" "light" "150" } { "light" "200" "origin" "1792 2176 -221" "classname" "light" } { "classname" "light" "origin" "1880 2288 -221" "light" "200" } { "light" "200" "origin" "2048 2288 -221" "classname" "light" } { "classname" "light" "origin" "2128 2208 -221" "light" "200" } { "light" "200" "origin" "2160 1992 -205" "classname" "light" } { "origin" "2288 1952 -29" "classname" "light" } { "light" "250" "origin" "2274 1738 -172" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "2274 1682 -172" "light" "250" } { "light" "200" "origin" "2376 2184 -152" "classname" "light" } { "light" "200" "origin" "2618 1658 -169" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "2618 1368 -169" "light" "200" } { "light" "200" "origin" "2176 1488 -169" "classname" "light_torch_small_walltorch" } { "light" "200" "origin" "2298 626 24" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1930 738 24" "light" "200" } { "light" "200" "origin" "2050 394 24" "classname" "light_torch_small_walltorch" } { "classname" "func_plat" "model" "*3" } { "light" "150" "origin" "2152 1784 -312" "classname" "light" } { "classname" "light" "origin" "2232 936 -4" "light" "200" } { "classname" "light" "origin" "2232 1040 48" } { "classname" "light_torch_small_walltorch" "origin" "2034 1034 -164" "light" "200" } { "classname" "light" "origin" "2304 1040 280" "light" "200" } { "light" "200" "origin" "2168 1040 280" "classname" "light" } { "origin" "2130 2452 -112" "classname" "light_flame_large_yellow" "light" "250" } { "classname" "light_flame_large_yellow" "origin" "1858 2452 -112" "light" "250" } { "classname" "light" "origin" "2132 2416 -188" "light" "150" } { "light" "150" "origin" "1860 2416 -188" "classname" "light" } { "light" "200" "origin" "2256 1968 -453" "classname" "light" } { "classname" "light" "origin" "2256 2184 -453" "light" "200" } { "light" "200" "origin" "2216 2384 -453" "classname" "light" } { "classname" "light" "origin" "1792 2400 -453" "light" "200" } { "light" "175" "origin" "1984 2400 -453" "classname" "light" } { "light" "150" "origin" "2168 1608 -9" "classname" "light" } { "classname" "light" "origin" "2368 1600 -9" "light" "150" } { "light" "150" "origin" "2240 1424 44" "classname" "light" } { "classname" "light" "origin" "2400 1424 44" "light" "150" } { "light" "150" "origin" "2560 1424 44" "classname" "light" } { "classname" "light" "origin" "2560 1560 44" "light" "175" } { "light" "150" "origin" "2232 1288 44" "classname" "light" } { "light" "175" "origin" "2384 1424 -160" "classname" "light" } { "classname" "light" "origin" "2232 1288 -160" "light" "175" } { "light" "150" "origin" "2164 932 -172" "classname" "light" } { "classname" "light" "origin" "2308 932 -172" "light" "150" } { "light" "150" "origin" "2232 776 24" "classname" "light" } { "classname" "light" "origin" "2192 664 24" "light" "150" } { "light" "150" "origin" "2016 696 24" "classname" "light" } { "classname" "light" "origin" "1912 496 24" "light" "150" } { "light" "175" "origin" "80 1616 -120" "classname" "light" } { "classname" "light" "origin" "72 1888 -120" "light" "175" } { "light" "175" "origin" "296 1616 -120" "classname" "light" } { "light" "175" "origin" "304 1888 -120" "classname" "light" } { "targetname" "t20" "angle" "90" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t21" "angle" "120" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t22" "angle" "150" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t19" "angle" "60" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t18" "angle" "30" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t17" "angle" "0" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t24" "angle" "210" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t23" "angle" "180" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t25" "angle" "240" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t26" "angle" "270" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t27" "angle" "300" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t28" "angle" "330" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "delay" ".1" "targetname" "t29" "target" "t17" "classname" "trigger_multiple" "model" "*4" } { "delay" ".1" "targetname" "t17" "target" "t18" "classname" "trigger_multiple" "model" "*5" } { "delay" ".1" "targetname" "t18" "target" "t19" "classname" "trigger_multiple" "model" "*6" } { "delay" ".1" "targetname" "t19" "target" "t20" "classname" "trigger_multiple" "model" "*7" } { "delay" ".1" "targetname" "t20" "target" "t21" "classname" "trigger_multiple" "model" "*8" } { "delay" ".1" "targetname" "t21" "target" "t22" "classname" "trigger_multiple" "model" "*9" } { "delay" ".1" "targetname" "t22" "target" "t23" "classname" "trigger_multiple" "model" "*10" } { "delay" ".1" "targetname" "t23" "target" "t24" "classname" "trigger_multiple" "model" "*11" } { "delay" ".1" "targetname" "t24" "target" "t25" "classname" "trigger_multiple" "model" "*12" } { "delay" ".1" "targetname" "t25" "target" "t26" "classname" "trigger_multiple" "model" "*13" } { "delay" ".1" "targetname" "t26" "target" "t27" "classname" "trigger_multiple" "model" "*14" } { "delay" ".1" "targetname" "t27" "target" "t28" "classname" "trigger_multiple" "model" "*15" } { "target" "t29" "wait" "1.3" "classname" "trigger_multiple" "model" "*16" } { "origin" "192 1750 -188" "classname" "light_flame_large_yellow" } { "light" "125" "origin" "214 1752 -166" "classname" "light" } { "classname" "light" "origin" "192 1774 -166" "light" "125" } { "light" "125" "origin" "170 1750 -166" "classname" "light" } { "classname" "light" "origin" "194 1726 -166" "light" "125" } { "target" "t31" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*17" } { "target" "t31" "angle" "180" "wait" "-1" "classname" "func_button" "model" "*18" } { "target" "t31" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*19" } { "target" "t31" "angle" "90" "wait" "-1" "classname" "func_button" "model" "*20" } { "wait" "-1" "targetname" "t30" "sounds" "4" "speed" "50" "angle" "-1" "classname" "func_door" "model" "*21" } { "count" "4" "targetname" "t31" "target" "t30" "classname" "trigger_counter" "model" "*22" } { "light" "150" "origin" "2424 1080 -176" "classname" "light" } { "classname" "light" "origin" "2424 992 -176" "light" "150" } { "targetname" "t40" "angle" "180" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "160" } { "targetname" "t40" "angle" "140" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "120" } { "targetname" "t40" "angle" "200" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "220" } { "targetname" "t40" "angle" "240" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t41" "target" "t40" "wait" ".5" "classname" "trigger_multiple" "model" "*23" } { "target" "t41" "classname" "trigger_multiple" "model" "*24" } { "target" "t41" "classname" "trigger_multiple" "model" "*25" } { "target" "t41" "classname" "trigger_multiple" "model" "*26" } { "target" "t41" "classname" "trigger_multiple" "model" "*27" } { "target" "t41" "classname" "trigger_multiple" "model" "*28" } { "target" "t41" "classname" "trigger_multiple" "model" "*29" } { "target" "t41" "classname" "trigger_multiple" "model" "*30" } { "light" "125" "origin" "2196 1200 -204" "classname" "light" } { "classname" "light" "origin" "2284 1200 -204" "light" "125" } { "light" "125" "origin" "2284 1112 -204" "classname" "light" } { "classname" "light" "origin" "2388 1104 -204" "light" "125" } { "light" "125" "origin" "2284 1000 -204" "classname" "light" } { "classname" "light" "origin" "2140 1008 -204" "light" "125" } { "light" "125" "origin" "2132 1096 -204" "classname" "light" } { "classname" "light" "origin" "2132 1160 -204" "light" "125" } { "light" "200" "origin" "528 1816 -392" "classname" "light" } { "classname" "light" "origin" "736 1808 -392" "light" "200" } { "light" "200" "origin" "1040 1808 -392" "classname" "light" } { "classname" "light" "origin" "744 1424 -392" "light" "200" } { "light" "200" "origin" "752 1288 -416" "classname" "light" } { "light" "200" "origin" "760 1064 -376" "classname" "light" } { "classname" "func_train" "spawnflags" "33" "targetname" "t42" "dmg" "1000" "sounds" "1" "target" "t124" "speed" "250" "model" "*31" } { "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t43" "speed" "50" "sounds" "3" "model" "*32" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t42" "sounds" "1" "model" "*33" } { "classname" "trigger_once" "target" "t43" "targetname" "t42" "delay" "2" "model" "*34" } { "classname" "light" "origin" "1936 1784 -288" "light" "125" } { "classname" "monster_ogre" "origin" "1976 1784 -328" "angle" "180" } { "classname" "func_door" "angle" "90" "wait" "-1" "sounds" "1" "model" "*35" } { "classname" "func_door" "angle" "270" "targetname" "t44" "wait" "-1" "model" "*36" } { "classname" "light" "origin" "64 264 8" "light" "125" } { "light" "125" "origin" "64 120 8" "classname" "light" } { "classname" "light" "origin" "64 192 8" "light" "100" } { "classname" "trigger_once" "target" "t44" "model" "*37" } { "classname" "light" "origin" "512 184 -8" "light" "175" } { "targetname" "t119" "classname" "func_door" "angle" "90" "wait" "-1" "speed" "40" "model" "*38" } { "targetname" "t119" "classname" "func_door" "wait" "-1" "angle" "270" "speed" "40" "sounds" "4" "model" "*39" } { "targetname" "t119" "classname" "func_door" "wait" "-1" "angle" "-1" "speed" "30" "message" "Go for a swim first..." "sounds" "3" "model" "*40" } { "classname" "func_button" "angle" "0" "wait" "-1" "target" "t45" "model" "*41" } { "classname" "light" "origin" "36 184 84" "light" "75" } { "classname" "light" "origin" "752 184 -192" "light" "150" } { "classname" "light" "origin" "544 536 -152" "light" "125" } { "classname" "func_door" "angle" "-2" "sounds" "1" "wait" "-1" "targetname" "t45" "model" "*42" } { "wait" "-1" "sounds" "1" "angle" "-2" "classname" "func_door" "targetname" "t45" "model" "*43" } { "light" "125" "origin" "544 -152 -152" "classname" "light" } { "classname" "item_artifact_envirosuit" "origin" "1024 492 -232" } { "classname" "item_armor1" "origin" "2128 1752 -352" } { "classname" "light_flame_small_yellow" "origin" "1024 368 -4" "light" "250" } { "classname" "light" "origin" "1024 400 -64" "light" "150" } { "wait" "5" "sounds" "1" "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t51" "model" "*44" } { "wait" "5" "sounds" "1" "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t51" "model" "*45" } { "sounds" "3" "classname" "func_button" "angle" "270" "wait" "3" "target" "t51" "model" "*46" } { "classname" "light" "origin" "1224 712 -216" "light" "100" } { "classname" "light" "origin" "1232 768 -192" "light" "100" } { "light" "75" "origin" "1168 760 -232" "classname" "light" } { "light" "100" "origin" "1232 800 -208" "classname" "light" } { "sounds" "1" "origin" "1860 472 -8" "classname" "item_key2" "spawnflags" "2048" } { "classname" "light" "origin" "1112 1568 -40" "light" "200" } { "light" "150" "origin" "-96 1440 -160" "classname" "light" } { "classname" "light" "origin" "384 1440 -160" "light" "150" } { "light" "200" "origin" "248 1408 -96" "classname" "light" } { "light" "150" "origin" "968 1480 -128" "classname" "light" } { "light" "150" "origin" "1008 -592 -32" "classname" "light" } { "classname" "light" "origin" "1264 -592 -32" "light" "150" } { "light" "200" "origin" "880 -840 -56" "classname" "light" } { "classname" "light" "origin" "1376 -856 -56" "light" "200" } { "light" "175" "origin" "264 184 -8" "classname" "light" } { "light" "175" "origin" "1464 -864 -208" "classname" "light" } { "light" "175" "origin" "1816 160 -56" "classname" "light" } { "classname" "light" "origin" "1560 160 -56" "light" "175" } { "light" "175" "origin" "1544 1632 104" "classname" "light" } { "classname" "light" "origin" "1792 1624 128" "light" "175" } { "classname" "item_health" "origin" "1068 -980 -104" } { "spawnflags" "1" "classname" "item_shells" "origin" "1344 -1160 -96" } { "classname" "monster_ogre" "origin" "1008 -128 40" "angle" "315" "targetname" "t59" "spawnflags" "1" } { "classname" "trigger_once" "target" "t59" "model" "*47" } { "classname" "monster_ogre" "origin" "896 96 56" "angle" "270" "target" "t60" "spawnflags" "1" } { "classname" "path_corner" "origin" "896 208 40" "target" "t60" "targetname" "t61" } { "origin" "896 -16 40" "classname" "path_corner" "targetname" "t60" "target" "t61" } { "classname" "path_corner" "origin" "168 392 -56" "target" "t62" "targetname" "t63" } { "origin" "168 -16 -56" "classname" "path_corner" "targetname" "t62" "target" "t63" } { "classname" "path_corner" "origin" "88 344 -56" "targetname" "t64" "target" "t65" "spawnflags" "256" } { "origin" "88 72 -56" "classname" "path_corner" "target" "t64" "targetname" "t65" "spawnflags" "256" } { "classname" "monster_hell_knight" "origin" "88 224 -40" "angle" "90" "target" "t64" "spawnflags" "257" } { "classname" "monster_hell_knight" "origin" "168 232 -40" "angle" "270" "target" "t62" "spawnflags" "1" } { "classname" "monster_zombie" "origin" "544 -120 -208" "angle" "90" "targetname" "t45" } { "classname" "monster_zombie" "origin" "544 496 -208" "angle" "270" "targetname" "t45" } { "classname" "monster_wizard" "origin" "664 428 216" "angle" "225" "spawnflags" "1" } { "angle" "135" "origin" "664 -56 216" "classname" "monster_wizard" "spawnflags" "257" } { "classname" "light" "origin" "1736 88 -40" "light" "100" } { "classname" "monster_ogre" "origin" "904 -120 56" "angle" "0" "targetname" "t66" "spawnflags" "1281" } { "classname" "trigger_once" "target" "t66" "spawnflags" "256" "model" "*48" } { "classname" "item_health" "origin" "1168 -408 -80" "spawnflags" "1" } { "classname" "item_health" "origin" "1168 -104 -16" } { "classname" "item_spikes" "origin" "928 216 32" } { "classname" "item_rockets" "origin" "632 -48 32" } { "classname" "item_health" "origin" "32 392 -64" } { "light" "200" "origin" "1688 288 148" "classname" "light" } { "classname" "light" "origin" "1688 464 148" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "1814 622 -64" "light" "250" } { "classname" "light" "origin" "1768 344 -72" "light" "200" } { "classname" "trigger_monsterjump" "angle" "0" "model" "*49" } { "targetname" "t100" "classname" "monster_ogre" "origin" "1504 272 24" "angle" "0" "spawnflags" "256" } { "targetname" "t68" "target" "t67" "origin" "1352 576 -120" "classname" "path_corner" "spawnflags" "256" } { "target" "t68" "targetname" "t67" "classname" "path_corner" "origin" "1352 416 -120" "spawnflags" "256" } { "target" "t68" "angle" "90" "origin" "1360 480 -104" "classname" "monster_demon1" "spawnflags" "257" } { "targetname" "t70" "target" "t69" "origin" "1472 496 -120" "classname" "path_corner" } { "target" "t70" "targetname" "t69" "classname" "path_corner" "origin" "1688 496 -120" } { "target" "t69" "angle" "270" "origin" "1648 544 -104" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t71" "targetname" "t72" "origin" "1984 688 -24" "classname" "path_corner" "spawnflags" "256" } { "target" "t72" "targetname" "t71" "classname" "path_corner" "origin" "1984 448 -24" "spawnflags" "256" } { "target" "t71" "angle" "270" "origin" "1992 536 -8" "classname" "monster_ogre" "spawnflags" "257" } { "target" "t74" "targetname" "t73" "origin" "2120 680 -24" "classname" "path_corner" } { "targetname" "t74" "target" "t73" "classname" "path_corner" "origin" "2240 680 -24" } { "target" "t74" "angle" "225" "origin" "2256 736 -8" "classname" "monster_ogre" "spawnflags" "1" } { "targetname" "t78" "angle" "90" "origin" "2232 1312 -8" "classname" "monster_ogre" "spawnflags" "256" } { "target" "t76" "angle" "90" "origin" "2232 1008 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "targetname" "t76" "target" "t75" "origin" "2120 968 -216" "classname" "path_corner" } { "target" "t76" "targetname" "t75" "classname" "path_corner" "origin" "2336 968 -216" } { "classname" "light" "origin" "2384 2400 -152" "light" "200" } { "targetname" "t77" "wait" "-1" "sounds" "1" "speed" "300" "angle" "-2" "classname" "func_door" "model" "*50" } { "targetname" "t77" "angle" "180" "origin" "2512 2312 -200" "classname" "monster_demon1" "spawnflags" "256" } { "targetname" "t77" "classname" "monster_demon1" "origin" "2512 2160 -200" "angle" "180" } { "classname" "item_health" "origin" "2504 2200 -224" } { "light" "150" "origin" "2536 2312 -128" "classname" "light" } { "classname" "light" "origin" "2536 2160 -128" "light" "150" } { "target" "t77" "classname" "trigger_once" "model" "*51" } { "spawnflags" "2" "origin" "2368 2336 -224" "classname" "item_health" } { "spawnflags" "1" "origin" "2504 2240 -224" "classname" "item_spikes" } { "origin" "2408 2072 -224" "classname" "item_shells" } { "target" "t78" "classname" "trigger_once" "model" "*52" } { "targetname" "t78" "angle" "90" "origin" "2240 1272 -200" "classname" "monster_demon1" } { "light" "150" "origin" "1120 1384 -40" "classname" "light" } { "light" "200" "origin" "1200 1248 -104" "classname" "light" } { "light" "250" "origin" "1288 1032 -4" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "1256 1032 -64" "classname" "light" } { "classname" "light_flame_small_yellow" "origin" "568 1032 -4" "light" "250" } { "classname" "light" "origin" "600 1032 -64" "light" "150" } { "light" "250" "origin" "888 1272 -4" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "888 1240 -64" "classname" "light" } { "light" "200" "origin" "608 1232 -108" "classname" "light" } { "target" "t79" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*53" } { "targetname" "t79" "message" "This door is opened near by..." "sounds" "3" "speed" "35" "angle" "-1" "wait" "-1" "classname" "func_door" "model" "*54" } { "light" "100" "origin" "580 1208 -148" "classname" "light" } { "light" "200" "origin" "1224 736 -8" "classname" "light" } { "target" "t80" "classname" "trigger_once" "model" "*55" } { "targetname" "t80" "angle" "315" "origin" "640 1088 128" "classname" "monster_wizard" } { "targetname" "t80" "classname" "monster_wizard" "origin" "616 720 128" "angle" "0" } { "targetname" "t80" "angle" "180" "origin" "1280 680 128" "classname" "monster_wizard" "spawnflags" "256" } { "target" "t82" "origin" "1248 1080 24" "classname" "monster_wizard" "spawnflags" "1" } { "targetname" "t82" "target" "t81" "origin" "1168 1064 8" "classname" "path_corner" } { "target" "t82" "targetname" "t81" "classname" "path_corner" "origin" "720 1064 8" } { "targetname" "t80" "classname" "monster_wizard" "origin" "584 1112 128" "angle" "315" "spawnflags" "256" } { "origin" "1256 944 -184" "classname" "item_health" } { "spawnflags" "1" "origin" "1116 584 -256" "classname" "item_spikes" } { "targetname" "t79" "angle" "315" "origin" "1000 1464 -168" "classname" "monster_ogre" } { "target" "t85" "targetname" "t86" "origin" "1456 1824 -192" "classname" "path_corner" "spawnflags" "256" } { "target" "t86" "targetname" "t85" "classname" "path_corner" "origin" "1456 1560 -192" "spawnflags" "256" } { "target" "t85" "angle" "270" "origin" "1456 1664 -176" "classname" "monster_ogre" "spawnflags" "256" } { "targetname" "t91" "angle" "270" "origin" "1560 1944 -320" "classname" "monster_zombie" "spawnflags" "256" } { "targetname" "t91" "classname" "monster_zombie" "origin" "1600 1912 -320" "angle" "270" } { "angle" "225" "origin" "1960 1984 -320" "classname" "monster_zombie" } { "targetname" "t91" "classname" "monster_zombie" "origin" "1904 1928 -320" "angle" "225" } { "targetname" "t91" "angle" "270" "origin" "1624 1768 -320" "classname" "monster_zombie" } { "target" "t87" "classname" "monster_zombie" "origin" "1696 1912 -320" "angle" "0" } { "target" "t89" "angle" "270" "origin" "1704 1800 -320" "classname" "monster_zombie" } { "target" "t87" "targetname" "t88" "origin" "1648 1912 -336" "classname" "path_corner" } { "target" "t88" "targetname" "t87" "classname" "path_corner" "origin" "1848 1904 -336" } { "targetname" "t90" "target" "t89" "origin" "1648 1824 -336" "classname" "path_corner" } { "target" "t90" "targetname" "t89" "classname" "path_corner" "origin" "1768 1752 -336" } { "target" "t91" "classname" "trigger_once" "model" "*56" } { "spawnflags" "1" "origin" "1496 1808 -200" "classname" "item_health" } { "spawnflags" "1" "origin" "1184 2176 -192" "classname" "item_health" } { "classname" "item_health" "origin" "1184 2128 -192" "spawnflags" "1" } { "spawnflags" "1" "origin" "1264 1680 -192" "classname" "item_health" } { "target" "t92" "targetname" "t93" "origin" "2376 2304 -216" "classname" "path_corner" } { "target" "t93" "targetname" "t92" "classname" "path_corner" "origin" "2376 1984 -216" } { "target" "t95" "targetname" "t94" "origin" "2144 1608 -216" "classname" "path_corner" } { "target" "t94" "targetname" "t95" "classname" "path_corner" "origin" "2376 1608 -216" } { "target" "t92" "angle" "270" "origin" "2376 2176 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "135" "origin" "2416 1760 -200" "classname" "monster_hell_knight" "spawnflags" "257" } { "target" "t94" "angle" "180" "origin" "2320 1608 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "90" "origin" "2152 1840 -200" "classname" "monster_ogre" "spawnflags" "257" } { "target" "t97" "targetname" "t96" "origin" "2096 2376 -216" "classname" "path_corner" "spawnflags" "256" } { "target" "t96" "targetname" "t97" "classname" "path_corner" "origin" "2232 2208 -216" "spawnflags" "256" } { "target" "t96" "angle" "135" "origin" "2200 2264 -200" "classname" "monster_wizard" "spawnflags" "257" } { "origin" "2104 1544 -224" "classname" "item_shells" } { "origin" "2176 1240 -32" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "2256 1240 -32" } { "origin" "1928 584 -32" "classname" "item_shells" } { "spawnflags" "1" "origin" "2040 1072 -32" "classname" "item_health" } { "classname" "item_health" "origin" "2040 1024 -32" "spawnflags" "1" } { "angle" "225" "origin" "2352 1160 -200" "classname" "monster_hell_knight" "spawnflags" "256" } { "angle" "180" "origin" "1864 1192 -216" "classname" "monster_zombie" } { "classname" "monster_zombie" "origin" "1776 1192 -216" "angle" "180" } { "target" "t99" "targetname" "t98" "origin" "1688 1192 -232" "classname" "path_corner" } { "target" "t98" "targetname" "t99" "classname" "path_corner" "origin" "1688 1048 -232" } { "target" "t98" "angle" "90" "origin" "1688 1112 -216" "classname" "monster_zombie" } { "origin" "536 416 32" "classname" "item_shells" } { "target" "t100" "classname" "trigger_once" "spawnflags" "256" "model" "*57" } { "origin" "1784 408 -128" "classname" "item_health" } { "classname" "item_health" "origin" "1784 448 -128" } { "origin" "1736 728 -128" "classname" "item_rockets" } { "target" "t101" "sounds" "1" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*58" } { "light" "250" "origin" "1418 234 52" "classname" "light_torch_small_walltorch" } { "targetname" "t101" "classname" "trigger_secret" "model" "*59" } { "targetname" "t102" "angle" "180" "classname" "trigger_monsterjump" "model" "*60" } { "target" "t102" "killtarget" "t102" "classname" "trigger_once" "model" "*61" } { "origin" "1568 1968 -352" "classname" "item_health" } { "classname" "item_health" "origin" "1608 1968 -352" } { "origin" "2112 1776 -352" "classname" "item_shells" "spawnflags" "2048" } { "origin" "1920 2232 -352" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "2008 2232 -352" } { "classname" "item_shells" "origin" "2176 1440 -224" } { "target" "t66" "classname" "trigger_once" "model" "*62" } { "origin" "1744 0 -128" "classname" "item_spikes" "spawnflags" "1" } { "target" "t103" "targetname" "t104" "origin" "-56 1432 -224" "classname" "path_corner" "spawnflags" "256" } { "target" "t104" "targetname" "t103" "classname" "path_corner" "origin" "312 1432 -224" "spawnflags" "256" } { "target" "t103" "origin" "40 1440 -208" "classname" "monster_ogre" "spawnflags" "257" } { "angle" "45" "origin" "56 1616 -208" "classname" "monster_hell_knight" "spawnflags" "1" } { "target" "t105" "targetname" "t106" "origin" "520 1816 -232" "classname" "path_corner" } { "target" "t106" "targetname" "t105" "classname" "path_corner" "origin" "920 1816 -232" } { "target" "t105" "origin" "624 1800 -216" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "0" "origin" "480 1824 64" "classname" "monster_wizard" "spawnflags" "257" } { "targetname" "t107" "classname" "monster_wizard" "origin" "656 1816 64" "angle" "0" "spawnflags" "1" } { "targetname" "t107" "angle" "0" "origin" "840 1816 64" "classname" "monster_wizard" "spawnflags" "257" } { "target" "t107" "classname" "trigger_once" "model" "*63" } { "origin" "1440 2200 -192" "classname" "item_shells" } { "classname" "item_shells" "origin" "1440 2160 -192" } { "spawnflags" "1" "origin" "1184 1976 -192" "classname" "item_spikes" } { "target" "t109" "targetname" "t108" "origin" "1240 2000 -184" "classname" "path_corner" } { "target" "t108" "targetname" "t109" "classname" "path_corner" "origin" "1240 1760 -184" } { "target" "t108" "angle" "90" "origin" "1240 1904 -168" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t110" "classname" "trigger_once" "spawnflags" "256" "model" "*64" } { "targetname" "t110" "angle" "45" "origin" "1216 2088 -168" "classname" "monster_ogre" "spawnflags" "1281" } { "classname" "item_health" "origin" "1496 1768 -200" } { "target" "t111" "classname" "trigger_once" "model" "*65" } { "targetname" "t111" "angle" "315" "origin" "764 -60 -208" "classname" "monster_zombie" } { "targetname" "t111" "angle" "45" "origin" "764 436 -208" "classname" "monster_zombie" } { "targetname" "t111" "angle" "225" "origin" "284 -56 -208" "classname" "monster_zombie" "spawnflags" "256" } { "targetname" "t119" "wait" "-1" "speed" "40" "angle" "90" "classname" "func_door" "model" "*66" } { "origin" "1280 592 -128" "classname" "item_shells" } { "classname" "item_shells" "origin" "576 416 32" } { "classname" "item_spikes" "origin" "904 504 -128" "spawnflags" "1" } { "origin" "904 464 -128" "classname" "item_spikes" "spawnflags" "1" } { "classname" "item_health" "origin" "1024 912 -152" "spawnflags" "1" } { "classname" "item_spikes" "origin" "720 848 -184" "spawnflags" "1" } { "classname" "path_corner" "origin" "1224 1192 -176" "targetname" "t112" "target" "t113" } { "origin" "1216 896 -176" "classname" "path_corner" "targetname" "t113" "target" "t112" } { "classname" "monster_ogre" "origin" "1224 992 -160" "angle" "90" "target" "t112" } { "classname" "item_shells" "origin" "968 1600 -184" } { "classname" "item_artifact_super_damage" "origin" "1444 308 -104" } { "classname" "light" "origin" "992 -128 72" "light" "100" } { "classname" "item_shells" "origin" "1672 1008 -240" } { "classname" "item_health" "origin" "2264 1320 -224" } { "classname" "monster_wizard" "origin" "2120 1664 -72" "angle" "315" "spawnflags" "1" } { "classname" "item_health" "origin" "2016 392 -32" } { "classname" "monster_hell_knight" "origin" "360 1744 -208" "angle" "90" "targetname" "t114" "spawnflags" "257" } { "classname" "trigger_once" "target" "t114" "spawnflags" "256" "model" "*67" } { "classname" "item_health" "origin" "352 1464 -232" } { "spawnflags" "1" "origin" "352 1392 -232" "classname" "item_health" } { "classname" "item_armorInv" "origin" "744 1424 -448" } { "classname" "item_health" "origin" "-56 320 -232" } { "origin" "-16 320 -232" "classname" "item_health" } { "targetname" "t117" "classname" "trigger_teleport" "target" "t115" "spawnflags" "2" "model" "*68" } { "delay" ".5" "targetname" "t117" "classname" "trigger_teleport" "target" "t116" "spawnflags" "2" "model" "*69" } { "classname" "monster_wizard" "origin" "2928 1816 -152" "angle" "180" "targetname" "t117" } { "angle" "180" "origin" "2928 1768 -152" "classname" "monster_wizard" "targetname" "t117" } { "classname" "info_teleport_destination" "origin" "1824 1920 -184" "angle" "225" "targetname" "t115" } { "classname" "info_teleport_destination" "origin" "1880 1544 -184" "angle" "180" "targetname" "t116" } { "classname" "trigger_once" "target" "t117" "model" "*70" } { "classname" "monster_zombie" "origin" "764 388 -208" "angle" "0" "targetname" "t111" } { "angle" "0" "origin" "764 -12 -208" "classname" "monster_zombie" "targetname" "t111" } { "classname" "monster_zombie" "origin" "408 -56 -208" "angle" "270" "targetname" "t111" } { "classname" "light" "origin" "1200 672 -240" "light" "125" } { "classname" "item_spikes" "origin" "72 392 -64" "spawnflags" "1" } { "classname" "item_spikes" "origin" "2368 920 -224" } { "origin" "2032 976 -224" "classname" "item_spikes" } { "classname" "light" "origin" "1416 2096 -112" "light" "150" } { "light" "150" "origin" "1240 2096 -112" "classname" "light" } { "classname" "item_spikes" "origin" "464 1824 -240" } { "origin" "504 1824 -240" "classname" "item_spikes" } { "classname" "item_shells" "origin" "-96 1472 -232" "spawnflags" "1" } { "classname" "item_health" "origin" "528 -172 -232" } { "classname" "item_health" "origin" "40 -64 -64" } { "light" "225" "classname" "light_torch_small_walltorch" "origin" "122 -86 -8" } { "origin" "134 462 -8" "classname" "light_torch_small_walltorch" "light" "225" } { "light" "250" "origin" "678 446 92" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "678 -70 92" "light" "250" } { "light" "150" "origin" "120 -56 -16" "classname" "light" } { "classname" "light" "origin" "136 424 -16" "light" "150" } { "light" "150" "origin" "600 184 296" "classname" "light" } { "classname" "light" "origin" "152 184 296" "light" "150" } { "light" "150" "origin" "368 376 296" "classname" "light" } { "classname" "light" "origin" "368 0 296" "light" "150" } { "light" "150" "origin" "352 192 232" "classname" "light" } { "light" "200" "origin" "64 408 168" "classname" "light" } { "classname" "light" "origin" "56 -48 168" "light" "200" } { "light" "125" "origin" "1520 1880 24" "classname" "light" } { "origin" "272 272 -232" "classname" "item_rockets" } { "targetname" "t45" "classname" "func_door" "angle" "-2" "sounds" "1" "wait" "-1" "model" "*71" } { "classname" "light" "origin" "416 -152 -152" "light" "125" } { "targetname" "t45" "angle" "90" "origin" "416 -120 -208" "classname" "monster_zombie" "spawnflags" "256" } { "origin" "400 524 -232" "classname" "item_health" } { "light" "125" "origin" "416 536 -152" "classname" "light" } { "targetname" "t45" "wait" "-1" "sounds" "1" "angle" "-2" "classname" "func_door" "model" "*72" } { "targetname" "t45" "angle" "270" "origin" "416 496 -208" "classname" "monster_zombie" "spawnflags" "256" } { "target" "t120" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*73" } { "target" "t120" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*74" } { "targetname" "t120" "target" "t119" "classname" "trigger_counter" "model" "*75" } { "light" "125" "origin" "1792 840 -112" "classname" "light" } { "classname" "light" "origin" "1584 840 -112" "light" "125" } { "light" "125" "origin" "1792 2280 -480" "classname" "light" } { "classname" "light" "origin" "1792 2144 -480" "light" "125" } { "origin" "1776 2232 -508" "classname" "item_health" } { "classname" "item_health" "origin" "1776 2192 -508" } { "light" "150" "origin" "1016 1696 -336" "classname" "light" } { "light" "125" "origin" "1080 1696 -280" "classname" "light" } { "light" "125" "origin" "1152 1696 -200" "classname" "light" } { "light" "150" "origin" "1096 1696 -352" "classname" "light" } { "classname" "trigger_secret" "model" "*76" } { "target" "t116" "classname" "trigger_teleport" "model" "*77" } { "spawnflags" "768" "angle" "315" "origin" "1400 1856 -176" "classname" "monster_ogre" } { "target" "t121" "targetname" "t122" "spawnflags" "768" "origin" "1824 2280 -344" "classname" "path_corner" } { "target" "t122" "targetname" "t121" "spawnflags" "768" "classname" "path_corner" "origin" "2080 2280 -344" } { "target" "t121" "spawnflags" "769" "angle" "180" "origin" "2128 2272 -328" "classname" "monster_demon1" } { "spawnflags" "2816" "origin" "1824 2072 -352" "classname" "item_shells" } { "spawnflags" "769" "angle" "90" "origin" "1792 2176 -144" "classname" "monster_wizard" } { "spawnflags" "769" "angle" "180" "origin" "2600 1640 -200" "classname" "monster_hell_knight" } { "spawnflags" "2816" "origin" "2096 1136 -32" "classname" "item_shells" } { "classname" "monster_wizard" "origin" "1872 1432 -72" "angle" "90" "spawnflags" "769" } { "classname" "monster_hell_knight" "origin" "2400 1032 -8" "angle" "180" "spawnflags" "769" } { "classname" "monster_demon1" "origin" "1000 496 -104" "angle" "0" "spawnflags" "768" } { "classname" "monster_demon1" "origin" "1240 2088 -168" "angle" "45" "spawnflags" "769" "targetname" "t110" } { "classname" "monster_hell_knight" "origin" "360 1936 -208" "angle" "270" "spawnflags" "769" "targetname" "t114" } { "classname" "item_shells" "origin" "16 1768 -232" "spawnflags" "2560" } { "spawnflags" "2560" "origin" "344 1576 -232" "classname" "item_shells" } { "classname" "trigger_changelevel" "map" "e2m4" "model" "*78" } { "classname" "light" "origin" "1136 -1144 264" "light" "250" } { "light" "250" "origin" "1264 -552 44" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "1008 -552 44" "light" "250" } { "classname" "monster_demon1" "origin" "888 -120 56" "angle" "0" "spawnflags" "769" "targetname" "t66" } { "classname" "monster_hell_knight" "origin" "616 184 56" "angle" "0" "spawnflags" "768" } { "classname" "item_spikes" "origin" "880 216 32" "spawnflags" "2816" } { "classname" "monster_hell_knight" "origin" "1944 728 -8" "angle" "0" "spawnflags" "769" } { "classname" "light" "origin" "-48 1184 -156" "light" "200" "style" "10" } { "style" "10" "light" "200" "origin" "0 1024 -120" "classname" "light" } { "classname" "light" "origin" "48 800 -120" "light" "200" "style" "10" } { "style" "10" "light" "200" "origin" "0 600 -120" "classname" "light" } { "classname" "monster_hell_knight" "origin" "128 1088 -208" "angle" "225" "spawnflags" "1" } { "angle" "315" "origin" "-104 760 -208" "classname" "monster_hell_knight" "spawnflags" "1" } { "classname" "item_spikes" "origin" "-56 592 -232" } { "classname" "item_health" "origin" "-56 920 -232" } { "classname" "monster_demon1" "origin" "0 544 -208" "angle" "90" "target" "t123" "spawnflags" "769" } { "mangle" "20 315 0" "origin" "1568 2040 -88" "classname" "info_intermission" } { "classname" "item_shells" "origin" "1528 1968 -352" "spawnflags" "3584" } { "origin" "-88 1376 -232" "classname" "item_health" "spawnflags" "3585" } { "classname" "item_artifact_envirosuit" "origin" "1216 1696 -168" "spawnflags" "3584" } { "classname" "monster_demon1" "origin" "144 372 -208" "angle" "180" "spawnflags" "768" "targetname" "t123" } { "classname" "monster_demon1" "origin" "0 528 -208" "angle" "90" "spawnflags" "1025" } { "classname" "info_player_deathmatch" "origin" "1128 -840 -80" "angle" "90" } { "classname" "info_player_deathmatch" "origin" "656 184 -208" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "-24 1440 -208" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "1240 1816 -168" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "1032 1568 -168" "angle" "0" } { "classname" "func_wall" "spawnflags" "1792" "model" "*79" } { "classname" "weapon_rocketlauncher" "origin" "184 1440 -232" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "1424 608 -104" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "2272 680 -8" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "2240 1472 -200" "angle" "270" } { "classname" "weapon_supernailgun" "origin" "2236 1184 -32" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "2424 1824 -200" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "1792 2072 -328" "angle" "270" } { "classname" "weapon_supershotgun" "origin" "1488 1584 -200" "spawnflags" "1792" } { "classname" "weapon_grenadelauncher" "origin" "88 184 -64" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "1224 840 -168" "angle" "90" } { "classname" "weapon_nailgun" "origin" "1024 872 -152" "spawnflags" "1792" } { "classname" "weapon_supershotgun" "origin" "136 1760 -232" "spawnflags" "1792" } { "classname" "weapon_nailgun" "origin" "1976 2288 -352" "spawnflags" "1792" } { "classname" "weapon_lightning" "origin" "2128 1792 -352" "spawnflags" "1792" } { "classname" "item_cells" "origin" "1608 728 -128" "spawnflags" "1792" } { "spawnflags" "1792" "classname" "item_cells" "origin" "72 1032 -232" } { "classname" "item_cells" "origin" "1008 1328 -192" "spawnflags" "1792" } { "classname" "item_cells" "origin" "1304 -1160 -96" "spawnflags" "1792" } { "origin" "2272 1440 -224" "classname" "item_shells" "spawnflags" "2816" } { "origin" "224 1736 -232" "classname" "item_health" } { "classname" "info_intermission" "origin" "1328 -1168 192" "mangle" "20 120 0" } { "classname" "info_intermission" "origin" "1248 680 8" "mangle" "20 130 0" } { "classname" "info_intermission" "origin" "1280 1824 -104" "mangle" "10 180 0" } { "classname" "light" "origin" "-304 888 -80" "light" "150" } { "light" "150" "origin" "-304 712 -80" "classname" "light" } { "classname" "light" "origin" "-224 872 -8" "light" "125" } { "classname" "light" "origin" "-224 728 -8" "light" "125" } { "light" "150" "origin" "-178 706 -156" "classname" "light_torch_small_walltorch" } { "classname" "light" "origin" "-320 838 -138" "light" "100" } { "light" "100" "origin" "-320 774 -138" "classname" "light" } { "classname" "info_player_coop" "origin" "1192 -1088 -72" "angle" "90" } { "angle" "90" "origin" "1080 -1088 -72" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "1008 -1112 -72" "angle" "90" } { "angle" "90" "origin" "1264 -1112 -72" "classname" "info_player_coop" } { "classname" "item_armor1" "origin" "784 1816 -232" } { "classname" "item_spikes" "origin" "-56 1472 -232" "spawnflags" "1" } { "classname" "item_rockets" "origin" "400 -172 -232" } { "classname" "func_wall" "spawnflags" "1792" "model" "*80" } { "spawnflags" "1792" "classname" "func_wall" "model" "*81" } { "classname" "path_corner" "origin" "1954 1770 -96" "targetname" "t124" "target" "t125" } { "classname" "path_corner" "origin" "1954 1770 -320" "targetname" "t125" "target" "t124" } { "classname" "weapon_grenadelauncher" "origin" "1688 720 -128" "spawnflags" "2048" } { "wait" "-1" "angle" "-2" "classname" "func_door" "targetname" "t126" "lip" "-8" "model" "*82" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "model" "*83" } { "classname" "light" "origin" "-224 832 -152" "light" "125" } { "classname" "trigger_counter" "target" "t126" "targetname" "t127" "spawnflags" "1" "count" "7" "model" "*84" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*85" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*86" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*87" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*88" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*89" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*90" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*91" } { "classname" "ambient_swamp1" "origin" "1338 -854 -104" } { "classname" "ambient_swamp2" "origin" "938 -854 -104" } { "classname" "ambient_drip" "origin" "1138 -854 -176" } { "classname" "ambient_drip" "origin" "1650 -862 -192" } { "classname" "ambient_drip" "origin" "1674 -438 -192" } { "classname" "ambient_drip" "origin" "1682 2 -48" } { "classname" "ambient_swamp1" "origin" "1674 1986 -280" } { "classname" "ambient_swamp2" "origin" "1826 2378 -280" } { "classname" "ambient_swamp1" "origin" "2258 2058 -280" } { "classname" "ambient_drip" "origin" "746 1370 -376" } { "classname" "ambient_drip" "origin" "762 906 -240" } { "origin" "1034 722 -240" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "554 1818 -352" } { "origin" "1002 1810 -352" "classname" "ambient_drip" } { "speed" "35" "classname" "func_door" "wait" "-1" "angle" "-2" "sounds" "1" "targetname" "t101" "model" "*92" } { "classname" "light" "origin" "1440 296 -80" "light" "125" } { "origin" "1792 792 -240" "classname" "item_spikes" } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e1m2.ent���������������������������������������������������������0000644�0000000�0000000�00000120507�12403131422�017033� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "message" "Castle of the Damned" "wad" "gfx/wizard.wad" "classname" "worldspawn" "worldtype" "0" "sounds" "8" } { "angle" "270" "origin" "1496 1664 296" "classname" "info_player_start" } { "origin" "1432 672 336" "classname" "light" "light" "250" } { "light" "200" "origin" "1496 888 272" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "932 640 340" } { "classname" "light_torch_small_walltorch" "origin" "1104 812 340" } { "classname" "light" "origin" "1104 640 544" "light" "300" } { "light" "175" "origin" "1216 536 353" "classname" "light" } { "light" "250" "origin" "1816 328 448" "classname" "light" } { "light" "200" "origin" "1632 472 208" "classname" "light" } { "light" "200" "origin" "1792 -392 240" "classname" "light" } { "light" "200" "origin" "1452 -124 508" "classname" "light" } { "light" "150" "origin" "1196 -124 508" "classname" "light" } { "light" "150" "origin" "1044 -124 508" "classname" "light" } { "light" "200" "origin" "756 -124 508" "classname" "light" } { "light" "250" "origin" "744 336 145" "classname" "light" } { "light" "200" "origin" "1176 -912 672" "classname" "light" } { "origin" "1328 -544 552" "classname" "light" } { "classname" "light" "origin" "1528 -912 640" "light" "200" } { "light" "200" "classname" "light" "origin" "880 -648 672" } { "origin" "240 -264 392" "classname" "light" "light" "250" } { "classname" "light" "origin" "-352 -504 464" "light" "200" } { "origin" "-448 -608 804" "classname" "light" "light" "450" } { "light" "250" "origin" "776 -912 472" "classname" "light" } { "light" "300" "origin" "1630 -806 428" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "1528 -912 464" "classname" "light" } { "classname" "light" "origin" "1180 -484 560" } { "classname" "light" "origin" "1184 -612 560" } { "classname" "light" "origin" "1016 -368 472" "light" "100" } { "classname" "light" "origin" "1016 -464 472" "light" "100" } { "classname" "light" "origin" "1020 -560 472" "light" "100" } { "classname" "light" "origin" "1208 -776 472" "light" "100" } { "classname" "light" "origin" "1288 -776 472" "light" "100" } { "classname" "light" "origin" "1360 -776 472" "light" "100" } { "light" "200" "origin" "1792 120 376" "classname" "light" } { "origin" "1538 182 356" "classname" "light_torch_small_walltorch" } { "light" "200" "origin" "1640 80 360" "classname" "light" } { "light" "200" "origin" "1928 80 360" "classname" "light" } { "light" "250" "origin" "1792 296 208" "classname" "light" } { "light" "150" "origin" "1800 40 160" "classname" "light" } { "light" "200" "origin" "1776 -392 160" "classname" "light" } { "light" "200" "origin" "1304 -392 152" "classname" "light" } { "light" "250" "origin" "1632 112 136" "classname" "light" } { "light" "250" "origin" "1432 312 136" "classname" "light" } { "light" "200" "origin" "1136 -656 160" "classname" "light" } { "light" "200" "origin" "1136 -416 160" "classname" "light" } { "light" "250" "origin" "1448 -552 160" "classname" "light" } { "light" "200" "origin" "1920 440 136" "classname" "light" } { "light" "200" "origin" "968 88 177" "classname" "light" } { "light" "300" "origin" "1088 312 129" "classname" "light" } { "light" "150" "origin" "1376 168 129" "classname" "light" } { "light" "250" "origin" "112 -384 392" "classname" "light" } { "origin" "300 -1004 508" "classname" "light" } { "origin" "296 -812 505" "classname" "light" } { "origin" "300 -1204 505" "classname" "light" } { "light" "150" "origin" "470 -1006 468" "classname" "light_torch_small_walltorch" } { "light" "250" "origin" "984 -1216 496" "classname" "light" } { "light" "250" "origin" "888 -1128 552" "classname" "light" } { "light" "200" "origin" "800 -1216 592" "classname" "light" } { "light" "200" "origin" "664 -1216 592" "classname" "light" } { "light" "200" "origin" "584 -1136 592" "classname" "light" } { "light" "200" "origin" "584 -968 592" "classname" "light" } { "light" "250" "origin" "584 -744 592" "classname" "light" } { "light" "200" "origin" "528 -1144 464" "classname" "light" } { "light" "200" "origin" "528 -856 464" "classname" "light" } { "light" "200" "classname" "light" "origin" "1496 1544 440" } { "origin" "1384 1392 440" "classname" "light" "light" "250" } { "origin" "1496 1104 520" "classname" "light" } { "origin" "1608 1400 440" "classname" "light" "light" "250" } { "light" "250" "origin" "1240 1712 360" "classname" "light" } { "light" "250" "origin" "1744 1696 360" "classname" "light" } { "classname" "light" "origin" "1384 1136 440" "light" "250" } { "classname" "light" "origin" "1608 1144 440" "light" "250" } { "classname" "path_corner" "origin" "1168 736 296" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "992 744 296" "targetname" "t6" "target" "t7" } { "classname" "path_corner" "origin" "1000 544 296" "targetname" "t7" "target" "t34" } { "classname" "item_health" "origin" "960 704 288" } { "classname" "item_shells" "origin" "952 512 288" } { "classname" "path_corner" "origin" "1344 -128 304" "targetname" "t9" "target" "t8" } { "classname" "path_corner" "origin" "898 -128 304" "targetname" "t8" "target" "t9" } { "spawnflags" "1" "classname" "monster_ogre" "origin" "1018 -126 320" "angle" "0" "target" "t8" } { "classname" "item_health" "origin" "1344 -224 296" "spawnflags" "1" } { "classname" "item_health" "origin" "1400 -224 296" "spawnflags" "1" } { "origin" "1528 192 296" "classname" "item_shells" } { "classname" "path_corner" "origin" "1496 1040 184" "targetname" "t22" "target" "t23" } { "classname" "path_corner" "origin" "1496 840 248" "targetname" "t23" "target" "t33" } { "spawnflags" "1" "classname" "item_shells" "origin" "1056 -648 288" } { "classname" "item_health" "origin" "1184 -736 288" } { "spawnflags" "257" "classname" "monster_army" "origin" "1646 -698 360" "angle" "180" "targetname" "t89" } { "classname" "path_corner" "origin" "1400 640 272" "targetname" "t30" "target" "t79" } { "classname" "path_corner" "origin" "1496 752 232" "targetname" "t33" "target" "t77" } { "classname" "path_corner" "origin" "1192 560 296" "targetname" "t34" "target" "t80" } { "classname" "item_shells" "origin" "1616 1280 176" } { "classname" "item_health" "origin" "1056 -840 416" "spawnflags" "1" } { "classname" "item_health" "origin" "1104 -840 416" "spawnflags" "1" } { "spawnflags" "1" "classname" "monster_army" "origin" "262 -458 320" "angle" "0" "target" "t96" } { "spawnflags" "1024" "classname" "item_health" "origin" "136 -296 296" } { "classname" "path_corner" "origin" "-536 -704 472" "targetname" "t42" "target" "t41" } { "classname" "path_corner" "origin" "-576 -416 472" "targetname" "t41" "target" "t42" } { "classname" "monster_knight" "origin" "-578 -654 480" "target" "t41" "spawnflags" "1" } { "classname" "item_shells" "origin" "-368 -752 456" } { "classname" "item_health" "origin" "-16 -520 360" "spawnflags" "1" } { "classname" "item_health" "origin" "-16 -576 360" "spawnflags" "1" } { "classname" "light" "origin" "1848 -568 320" "light" "200" } { "classname" "light" "origin" "1760 -560 408" "light" "200" } { "classname" "light" "origin" "1624 -560 352" "light" "150" } { "targetname" "t43" "angle" "270" "origin" "800 368 312" "classname" "info_teleport_destination" } { "origin" "752 168 296" "classname" "item_health" } { "target" "t43" "classname" "trigger_teleport" "model" "*1" } { "origin" "1712 -568 256" "classname" "item_health" } { "classname" "monster_ogre" "origin" "1494 1134 208" "angle" "270" "target" "t22" } { "light" "300" "origin" "1856 1288 384" "classname" "light" } { "classname" "light" "origin" "1136 1288 384" } { "light" "200" "origin" "1920 328 380" "classname" "light" } { "target" "t122" "spawnflags" "2048" "sounds" "1" "classname" "item_key1" "origin" "880 -300 464" } { "light" "300" "origin" "648 -384 430" "classname" "light_flame_small_yellow" } { "light" "250" "classname" "light_flame_small_yellow" "origin" "1104 -224 406" } { "light" "250" "origin" "1456 -128 406" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "988 532 353" "light" "175" } { "light" "125" "origin" "1100 648 328" "classname" "light" } { "origin" "1616 936 310" "classname" "light_flame_small_yellow" "light" "300" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "1360 936 310" } { "origin" "1792 504 390" "classname" "light_flame_small_yellow" "light" "300" } { "origin" "1972 -252 332" "classname" "info_null" "targetname" "t47" } { "light" "800" "origin" "1992 -252 336" "classname" "light" "target" "t47" } { "classname" "info_null" "origin" "1948 -292 332" "targetname" "t48" } { "light" "800" "classname" "light" "origin" "1948 -312 336" "target" "t48" } { "origin" "880 -328 562" "classname" "light_flame_small_yellow" "light" "300" } { "classname" "light" "origin" "1056 -1288 504" } { "origin" "1184 -1288 504" "classname" "light" } { "classname" "light" "origin" "1312 -1288 504" } { "origin" "1440 -1288 504" "classname" "light" } { "sounds" "1" "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t50" "model" "*2" } { "sounds" "1" "classname" "func_door" "wait" "-1" "angle" "-2" "targetname" "t50" "model" "*3" } { "classname" "trigger_once" "target" "t50" "model" "*4" } { "classname" "light" "origin" "1368 -1016 504" "light" "200" } { "light" "200" "origin" "1120 -1024 504" "classname" "light" } { "classname" "light" "origin" "1248 -1184 464" "light" "175" } { "classname" "light" "origin" "776 -480 480" "light" "225" } { "classname" "light" "origin" "1904 -144 168" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "1706 -206 316" "light" "300" } { "light" "300" "origin" "2134 -34 316" "classname" "light_torch_small_walltorch" } { "origin" "1152 -296 422" "classname" "light_flame_small_yellow" "light" "250" } { "light" "250" "classname" "light_flame_small_yellow" "origin" "1152 -760 422" } { "origin" "1528 -556 478" "classname" "light_flame_small_yellow" "light" "250" } { "targetname" "t52" "origin" "1532 -552 328" "classname" "info_null" } { "origin" "1340 -544 384" "classname" "item_armor2" } { "sounds" "1" "targetname" "t53" "lip" "64" "wait" "-1" "angle" "-1" "classname" "func_door" "model" "*5" } { "sounds" "1" "targetname" "t53" "classname" "func_door" "angle" "-1" "wait" "-1" "lip" "64" "model" "*6" } { "targetname" "t53" "target" "t54" "classname" "trigger_teleport" "spawnflags" "2" "model" "*7" } { "targetname" "t54" "angle" "180" "origin" "1408 -688 449" "classname" "info_teleport_destination" } { "targetname" "t53" "target" "t57" "classname" "trigger_teleport" "spawnflags" "2" "model" "*8" } { "targetname" "t57" "angle" "180" "origin" "1408 -400 361" "classname" "info_teleport_destination" } { "spawnflags" "768" "targetname" "t53" "angle" "180" "origin" "1912 -856 217" "classname" "monster_wizard" } { "spawnflags" "768" "targetname" "t53" "classname" "monster_wizard" "origin" "1912 -936 217" "angle" "180" } { "targetname" "t50" "angle" "90" "origin" "1320 -1112 441" "classname" "monster_knight" } { "spawnflags" "256" "targetname" "t50" "angle" "0" "origin" "1056 -1144 441" "classname" "monster_knight" } { "sounds" "1" "targetname" "t61" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*9" } { "sounds" "3" "lip" "64" "spawnflags" "1" "targetname" "t58" "angle" "270" "wait" "-1" "classname" "func_door" "model" "*10" } { "sounds" "1" "wait" "-1" "angle" "270" "target" "t58" "classname" "func_button" "model" "*11" } { "target" "t61" "classname" "trigger_once" "model" "*12" } { "light" "225" "origin" "984 -480 480" "classname" "light" } { "light" "175" "origin" "880 -368 176" "classname" "light" } { "classname" "light" "origin" "880 -592 240" "light" "175" } { "light" "200" "origin" "880 -488 184" "classname" "light" } { "light" "150" "origin" "880 -304 472" "classname" "light" } { "classname" "light" "origin" "-96 308 864" "light" "850" } { "origin" "-32 -440 624" "classname" "light" } { "sounds" "1" "targetname" "t73" "wait" "-1" "lip" "196" "angle" "-1" "classname" "func_door" "model" "*13" } { "light" "300" "origin" "104 144 688" "classname" "light" } { "classname" "light" "origin" "-264 144 688" "light" "300" } { "sounds" "1" "targetname" "t73" "wait" "-1" "classname" "func_door" "angle" "-1" "lip" "196" "model" "*14" } { "classname" "light_flame_small_yellow" "origin" "-24 -232 414" "light" "250" } { "lip" "-2" "sounds" "3" "speed" "350" "targetname" "t73" "angle" "180" "wait" "-1" "classname" "func_door" "model" "*15" } { "target" "t63" "targetname" "t62" "origin" "-12 312 264" "classname" "path_corner" } { "target" "t64" "targetname" "t63" "origin" "-12 312 356" "classname" "path_corner" } { "wait" "-1" "target" "t66" "targetname" "t64" "classname" "path_corner" "origin" "-13 440 355" } { "sounds" "1" "targetname" "t71" "wait" "-1" "target" "t65" "angle" "-2" "classname" "func_button" "model" "*16" } { "target" "t64" "targetname" "t66" "origin" "-13 440 355" "classname" "path_corner" } { "light" "200" "origin" "-96 440 376" "classname" "light" } { "light" "150" "origin" "8 456 376" "classname" "light" } { "targetname" "t70" "target" "t67" "classname" "path_corner" "origin" "-220 312 264" } { "target" "t68" "targetname" "t67" "classname" "path_corner" "origin" "-220 312 356" } { "wait" "-1" "target" "t69" "targetname" "t68" "origin" "-221 440 355" "classname" "path_corner" } { "target" "t68" "targetname" "t69" "classname" "path_corner" "origin" "-221 440 355" } { "classname" "light" "origin" "-200 456 376" "light" "150" } { "targetname" "t65" "target" "t62" "classname" "func_train" "speed" "50" "sounds" "1" "model" "*17" } { "light" "250" "origin" "-96 632 406" "classname" "light_flame_small_yellow" } { "targetname" "t72" "origin" "-96 288 304" "classname" "info_null" } { "light" "450" "target" "t72" "origin" "-96 288 368" "classname" "light" } { "target" "t70" "targetname" "t65" "speed" "50" "classname" "func_train" "sounds" "1" "model" "*18" } { "lip" "-2" "sounds" "0" "speed" "350" "classname" "func_door" "wait" "-1" "angle" "0" "model" "*19" } { "targetname" "t65" "delay" "4.7" "target" "t73" "classname" "trigger_once" "model" "*20" } { "targetname" "t73" "angle" "270" "origin" "-96 552 320" "classname" "monster_demon1" "spawnflags" "1024" } { "targetname" "t74" "angle" "90" "origin" "132 -192 476" "classname" "info_teleport_destination" } { "targetname" "t75" "classname" "info_teleport_destination" "origin" "-328 -196 476" "angle" "90" } { "target" "t75" "classname" "trigger_teleport" "spawnflags" "1" "model" "*21" } { "target" "t74" "classname" "trigger_teleport" "spawnflags" "1" "model" "*22" } { "light" "200" "origin" "-418 306 356" "classname" "light" } { "classname" "light" "origin" "260 308 356" "light" "200" } { "sounds" "0" "targetname" "t73" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*23" } { "sounds" "0" "targetname" "t73" "wait" "-1" "angle" "0" "classname" "func_door" "model" "*24" } { "sounds" "0" "wait" "-1" "angle" "0" "targetname" "t73" "classname" "func_door" "model" "*25" } { "sounds" "0" "targetname" "t73" "angle" "180" "wait" "-1" "classname" "func_door" "model" "*26" } { "sounds" "3" "wait" "-1" "angle" "-2" "targetname" "t73" "classname" "func_door" "model" "*27" } { "classname" "light" "origin" "-96 24 360" "light" "100" } { "light" "100" "origin" "-96 -40 360" "classname" "light" } { "classname" "light" "origin" "-160 -568 624" } { "origin" "-160 -440 624" "classname" "light" } { "classname" "light" "origin" "-32 -568 624" } { "classname" "light" "origin" "-96 -88 484" "light" "150" } { "classname" "light" "origin" "-440 -408 804" "light" "450" } { "classname" "light" "origin" "600 -128 352" "light" "200" } { "classname" "light" "origin" "576 -608 504" "light" "250" } { "classname" "light" "origin" "384 -504 392" "light" "250" } { "classname" "light" "origin" "1264 240 295" "light" "250" } { "light" "250" "origin" "944 240 295" "classname" "light" } { "classname" "path_corner" "origin" "1480 704 264" "targetname" "t77" "target" "t78" } { "classname" "path_corner" "origin" "1448 656 264" "targetname" "t78" "target" "t30" } { "classname" "path_corner" "origin" "1264 640 304" "targetname" "t80" "target" "t5" } { "classname" "path_corner" "origin" "1328 640 304" "targetname" "t79" "target" "t80" } { "light" "200" "origin" "1488 -392 216" "classname" "light" } { "classname" "path_corner" "origin" "816 80 304" "targetname" "t83" "target" "t82" "spawnflags" "256" } { "origin" "816 312 304" "classname" "path_corner" "targetname" "t82" "target" "t83" "spawnflags" "256" } { "classname" "monster_army" "origin" "806 206 320" "angle" "90" "target" "t82" "spawnflags" "256" } { "classname" "trigger_once" "target" "t84" "model" "*28" } { "classname" "monster_ogre" "origin" "1790 -146 312" "angle" "90" "targetname" "t84" } { "classname" "path_corner" "origin" "1088 -672 296" "target" "t85" "targetname" "t88" } { "origin" "1088 -376 296" "classname" "path_corner" "targetname" "t85" "target" "t86" } { "classname" "path_corner" "origin" "1088 -376 296" "targetname" "t87" "target" "t88" } { "origin" "1448 -376 296" "classname" "path_corner" "targetname" "t86" "target" "t87" } { "spawnflags" "1" "classname" "monster_ogre" "origin" "1086 -498 312" "angle" "270" "target" "t88" } { "spawnflags" "256" "classname" "trigger_once" "target" "t89" "model" "*29" } { "classname" "item_health" "origin" "352 -752 408" "spawnflags" "1025" } { "spawnflags" "1025" "origin" "352 -792 408" "classname" "item_health" } { "classname" "item_health" "origin" "352 -832 408" "spawnflags" "1" } { "classname" "path_corner" "origin" "408 -776 416" "targetname" "t94" "target" "t95" } { "origin" "400 -1088 416" "classname" "path_corner" "targetname" "t95" "target" "t94" } { "classname" "path_corner" "origin" "584 -1096 416" "targetname" "t92" "target" "t93" } { "origin" "584 -792 416" "classname" "path_corner" "targetname" "t93" "target" "t92" } { "classname" "monster_army" "origin" "390 -970 432" "angle" "0" "target" "t94" } { "classname" "monster_army" "origin" "566 -970 432" "angle" "270" "target" "t92" } { "classname" "path_corner" "origin" "208 -304 304" "targetname" "t97" "target" "t96" } { "classname" "path_corner" "origin" "208 -464 304" "targetname" "t96" "target" "t97" } { "spawnflags" "1280" "classname" "path_corner" "origin" "-344 160 304" "targetname" "t100" "target" "t99" } { "spawnflags" "1280" "origin" "168 152 304" "classname" "path_corner" "targetname" "t99" "target" "t100" } { "spawnflags" "1280" "classname" "monster_ogre" "origin" "240 152 320" "angle" "180" "target" "t99" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "-392 80 320" "angle" "0" "targetname" "t101" } { "spawnflags" "768" "classname" "trigger_once" "target" "t101" "model" "*30" } { "classname" "item_health" "origin" "40 -16 464" } { "origin" "80 -48 464" "classname" "item_health" } { "origin" "520 -72 296" "classname" "item_shells" } { "spawnflags" "1" "origin" "-424 -216 296" "classname" "item_shells" } { "spawnflags" "769" "angle" "270" "origin" "880 -400 568" "classname" "monster_wizard" } { "light" "200" "origin" "432 176 152" "classname" "light" } { "light" "150" "origin" "432 -56 256" "classname" "light" } { "origin" "264 -96 300" "classname" "item_health" } { "classname" "item_health" "origin" "264 -140 300" } { "spawnflags" "1" "origin" "1184 1568 240" "classname" "item_health" } { "classname" "item_health" "origin" "1184 1616 240" "spawnflags" "1" } { "light" "150" "origin" "1496 1112 108" "classname" "light" } { "light" "200" "origin" "1120 1152 96" "classname" "light" } { "light" "200" "origin" "1080 692 184" "classname" "light" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "832 1184 294" } { "origin" "464 536 358" "classname" "light_flame_small_yellow" "light" "300" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "600 704 334" } { "light" "150" "origin" "1736 1096 110" "classname" "light" } { "light" "100" "origin" "832 1056 134" "classname" "light" } { "light" "150" "origin" "784 704 294" "classname" "light" } { "origin" "856 592 182" "classname" "item_health" } { "classname" "item_health" "origin" "824 552 182" } { "classname" "info_player_deathmatch" "origin" "-416 -144 320" "angle" "90" } { "classname" "info_player_deathmatch" "origin" "168 -480 320" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "1496 1328 200" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "1936 -136 312" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "936 -1216 432" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "792 -992 440" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "1080 -720 312" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "408 -752 432" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "792 -208 320" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "784 808 206" "angle" "225" } { "sounds" "3" "wait" "3" "angle" "90" "classname" "func_door" "model" "*31" } { "sounds" "0" "wait" "3" "angle" "270" "classname" "func_door" "model" "*32" } { "spawnflags" "1" "origin" "680 832 182" "classname" "item_shells" } { "origin" "1392 240 300" "classname" "weapon_supershotgun" } { "spawnflags" "769" "angle" "270" "origin" "954 -754 444" "classname" "monster_ogre" } { "spawnflags" "1" "origin" "520 -1280 408" "classname" "item_shells" } { "light" "200" "origin" "-612 -500 548" "classname" "light" } { "classname" "func_door" "angle" "91" // svdijk -- changed to prevent z-fighting (was "90") "targetname" "t110" "wait" "-1" "model" "*33" } { "sounds" "3" "classname" "func_door" "angle" "269" // svdijk -- changed to prevent z-fighting (was "270") "wait" "-1" "model" "*34" } { "classname" "trigger_once" "target" "t110" "model" "*35" } { "classname" "trigger_changelevel" "map" "e1m3" "model" "*36" } { "spawnflags" "1792" "origin" "680 728 184" "classname" "weapon_rocketlauncher" } { "spawnflags" "1792" "origin" "1496 1256 176" "classname" "weapon_nailgun" } { "angle" "180" "spawnflags" "1792" "origin" "-96 -496 360" "classname" "weapon_supernailgun" } { "spawnflags" "1794" "origin" "-112 -8 464" "classname" "item_health" } { "spawnflags" "1793" "origin" "-112 -568 360" "classname" "item_spikes" } { "spawnflags" "1792" "origin" "1616 1424 176" "classname" "item_spikes" } { "spawnflags" "1792" "classname" "item_spikes" "origin" "1656 1424 176" } { "spawnflags" "1792" "origin" "1696 1424 176" "classname" "item_spikes" } { "spawnflags" "768" "target" "t34" "angle" "315" "origin" "1070 646 312" "classname" "monster_ogre" } { "spawnflags" "768" "targetname" "t84" "angle" "90" "origin" "1624 88 376" "classname" "monster_wizard" } { "spawnflags" "768" "angle" "90" "targetname" "t84" "origin" "1866 -378 312" "classname" "monster_ogre" } { "angle" "45" "origin" "1088 -1096 440" "classname" "monster_knight" "targetname" "t50" } { "spawnflags" "768" "classname" "monster_knight" "origin" "1400 -1144 440" "angle" "90" "targetname" "t50" } { "spawnflags" "256" "target" "t111" "targetname" "t112" "origin" "896 -1216 416" "classname" "path_corner" } { "spawnflags" "256" "target" "t112" "targetname" "t111" "classname" "path_corner" "origin" "704 -1216 416" } { "spawnflags" "257" "target" "t111" "angle" "180" "origin" "758 -1218 432" "classname" "monster_army" } { "spawnflags" "768" "target" "t114" "targetname" "t113" "origin" "-96 -520 368" "classname" "path_corner" } { "spawnflags" "768" "target" "t113" "targetname" "t114" "origin" "-96 -152 304" "classname" "path_corner" } { "targetname" "t116" "spawnflags" "769" "target" "t113" "angle" "270" "origin" "-98 -194 320" "classname" "monster_ogre" } { "spawnflags" "1536" "origin" "1936 -96 289" "classname" "item_health" } { "spawnflags" "1025" "origin" "1040 -1200 417" "classname" "item_health" } { "spawnflags" "769" "target" "t117" "angle" "315" "origin" "-560 -312 592" "classname" "monster_wizard" } { "spawnflags" "768" "target" "t118" "targetname" "t117" "origin" "-528 -344 576" "classname" "path_corner" } { "spawnflags" "768" "target" "t117" "targetname" "t118" "origin" "-352 -656 576" "classname" "path_corner" } { "classname" "light" "origin" "1360 976 224" "light" "150" } { "light" "150" "origin" "1616 976 224" "classname" "light" } { "classname" "light" "origin" "1208 1296 368" "light" "250" } { "origin" "1784 1288 368" "classname" "light" "light" "250" } { "classname" "light" "origin" "1496 1664 336" "light" "250" } { "classname" "light" "origin" "1752 1176 112" "light" "150" } { "light" "200" "origin" "1776 976 112" "classname" "light" } { "classname" "light" "origin" "1216 976 112" "light" "200" } { "light" "150" "origin" "1224 1176 112" "classname" "light" } { "classname" "light" "origin" "1496 1432 520" "light" "250" } { "classname" "light" "origin" "1496 1304 264" "light" "200" } { "classname" "light" "origin" "1496 1432 288" "light" "200" } { "classname" "light" "origin" "1608 1120 88" "light" "150" } { "light" "150" "origin" "1384 1120 88" "classname" "light" } { "classname" "light" "origin" "1496 864 368" "light" "150" } { "light" "175" "origin" "980 764 353" "classname" "light" } { "classname" "light" "origin" "1228 764 353" "light" "175" } { "classname" "light" "origin" "1104 464 353" "light" "200" } { "classname" "light" "origin" "1104 -40 423" "light" "200" } { "light" "150" "origin" "1416 -128 367" "classname" "light" } { "classname" "light" "origin" "1104 -184 367" "light" "200" } { "classname" "light" "origin" "1184 56 423" "light" "150" } { "light" "150" "origin" "1024 56 423" "classname" "light" } { "classname" "light" "origin" "1272 -64 399" "light" "150" } { "light" "150" "origin" "888 -64 399" "classname" "light" } { "classname" "light" "origin" "1104 152 129" "light" "300" } { "classname" "light" "origin" "976 392 129" "light" "200" } { "classname" "light" "origin" "1104 656 120" } { "classname" "light" "origin" "896 712 144" "light" "200" } { "classname" "light" "origin" "640 704 280" "light" "200" } { "classname" "light" "origin" "464 496 296" "light" "150" } { "classname" "light" "origin" "888 1152 96" "light" "200" } { "classname" "light" "origin" "840 880 240" "light" "200" } { "classname" "light" "origin" "848 584 240" "light" "150" } { "classname" "light" "origin" "784 160 144" "light" "200" } { "classname" "light" "origin" "440 336 144" "light" "150" } { "light" "150" "origin" "584 336 144" "classname" "light" } { "classname" "light" "origin" "432 24 136" "light" "150" } { "classname" "light" "origin" "656 328 224" "light" "200" } { "classname" "light" "origin" "432 -128 312" "light" "200" } { "classname" "light" "origin" "600 -384 360" "light" "200" } { "origin" "520 -128 406" "classname" "light_flame_small_yellow" "light" "250" } { "classname" "light" "origin" "424 -320 352" "light" "200" } { "classname" "light" "origin" "664 -1216 472" "light" "150" } { "classname" "light" "origin" "336 -1208 504" "light" "150" } { "light" "150" "origin" "336 -1008 504" "classname" "light" } { "classname" "light" "origin" "336 -816 504" "light" "150" } { "classname" "light" "origin" "880 -1000 496" "light" "200" } { "classname" "light" "origin" "880 -792 496" "light" "200" } { "classname" "light" "origin" "880 -376 304" "light" "200" } { "classname" "light" "origin" "1048 -912 480" "light" "225" } { "classname" "light" "origin" "1120 -1192 468" "light" "150" } { "light" "150" "origin" "1376 -1192 468" "classname" "light" } { "classname" "light" "origin" "1472 -912 464" "light" "175" } { "classname" "light" "origin" "880 -304 480" "light" "100" } { "classname" "light" "origin" "880 -680 480" "light" "175" } { "classname" "light" "origin" "1600 -704 484" "light" "150" } { "classname" "light" "origin" "1504 -704 348" "light" "175" } { "light" "175" "origin" "1336 -704 348" "classname" "light" } { "classname" "light" "origin" "1152 -640 332" "light" "200" } { "classname" "light" "origin" "1096 -552 348" "light" "150" } { "light" "200" "origin" "1160 -456 332" "classname" "light" } { "light" "150" "origin" "1216 -384 348" "classname" "light" } { "classname" "light" "origin" "1344 -384 348" "light" "150" } { "classname" "light" "origin" "1544 392 156" "light" "225" } { "light" "225" "origin" "1848 248 156" "classname" "light" } { "classname" "light" "origin" "1936 136 156" "light" "225" } { "light" "200" "origin" "2096 -80 156" "classname" "light" } { "light" "200" "origin" "2048 -408 156" "classname" "light" } { "classname" "light" "origin" "1456 -392 444" "light" "225" } { "classname" "light" "origin" "1640 -384 352" "light" "225" } { "classname" "light_torch_small_walltorch" "origin" "2134 -474 316" "light" "250" } { "light" "200" "origin" "168 216 496" "classname" "light" } { "classname" "light" "origin" "-328 208 496" "light" "200" } { "light" "200" "origin" "-96 360 432" "classname" "light" } { "classname" "light" "origin" "-96 144 432" "light" "200" } { "light" "200" "origin" "-376 32 432" "classname" "light" } { "light" "200" "origin" "208 -72 432" "classname" "light" } { "light" "150" "origin" "-96 72 360" "classname" "light" } { "light" "150" "origin" "-64 -232 368" "classname" "light" } { "light" "150" "origin" "-96 -320 560" "classname" "light" } { "light" "250" "origin" "-96 -496 448" "classname" "light" } { "light" "150" "origin" "-416 -104 392" "classname" "light" } { "light" "150" "origin" "-344 -152 528" "classname" "light" } { "classname" "light" "origin" "160 -152 528" "light" "150" } { "light" "150" "origin" "-96 8 528" "classname" "light" } { "light" "200" "origin" "-560 -504 688" "classname" "light" } { "classname" "light" "origin" "-440 -368 688" "light" "200" } { "light" "200" "origin" "-440 -656 688" "classname" "light" } { "classname" "light" "origin" "-336 -504 688" "light" "200" } { "classname" "light" "origin" "2084 -208 336" "light" "100" } { "light" "100" "origin" "2012 -252 332" "classname" "light" } { "classname" "light" "origin" "1948 -328 332" "light" "100" } { "light" "150" "origin" "1892 -452 332" "classname" "light" } { "sounds" "1" "targetname" "t120" "wait" "-1" "angle" "-2" "classname" "func_door" "lip" "4" "model" "*37" } { "target" "t120" "classname" "trigger_once" "model" "*38" } { "light" "100" "origin" "2076 -312 336" "classname" "light" } { "sounds" "3" "spawnflags" "2064" "angle" "0" "wait" "-1" "classname" "func_door" "model" "*39" } { "spawnflags" "2064" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*40" } { "light" "100" "origin" "332 -264 356" "classname" "light" } { "classname" "light" "origin" "144 -264 356" "light" "100" } { "light" "100" "origin" "1104 572 316" "classname" "light" } { "target" "t121" "wait" ".8" "classname" "trigger_multiple" "model" "*41" } { "targetname" "t121" "angle" "180" "origin" "2120 -256 332" "classname" "trap_spikeshooter" "spawnflags" "1024" } { "targetname" "t121" "angle" "90" "origin" "1944 -456 332" "classname" "trap_spikeshooter" "spawnflags" "1024" } { "light" "150" "origin" "1312 -856 472" "classname" "light" } { "classname" "light" "origin" "1184 -856 472" "light" "175" } { "classname" "light" "origin" "1560 -568 224" "light" "200" } { "classname" "func_door" "angle" "-2" "wait" "-1" "speed" "50" "sounds" "1" "targetname" "t123" "lip" "6" "model" "*42" } { "classname" "trigger_once" "target" "t123" "model" "*43" } { "classname" "light" "origin" "1496 -552 330" "light" "700" "target" "t52" } { "classname" "light" "origin" "1288 80 140" "light" "250" } { "classname" "light" "origin" "1288 400 80" "light" "200" } { "classname" "light" "origin" "1328 -664 160" "light" "200" } { "classname" "item_armor1" "origin" "784 56 304" } { "classname" "light" "origin" "1544 464 352" "light" "75" } { "classname" "func_plat" "model" "*44" } { "classname" "light" "origin" "1496 1192 280" "light" "200" } { "classname" "light" "origin" "1608 1192 136" "light" "100" } { "light" "100" "origin" "1384 1184 136" "classname" "light" } { "light" "100" "origin" "1608 1048 136" "classname" "light" } { "classname" "light" "origin" "1384 1048 136" "light" "100" } { "classname" "light" "origin" "1200 1148 92" "light" "150" } { "light" "150" "origin" "876 -184 367" "classname" "light" } { "classname" "light" "origin" "768 -128 384" "light" "200" } { "classname" "light" "origin" "1104 388 552" "light" "250" } { "light" "200" "origin" "1392 240 384" "classname" "light" } { "classname" "light" "origin" "1392 80 368" "light" "200" } { "classname" "light" "origin" "1272 400 367" "light" "150" } { "light" "150" "origin" "920 400 367" "classname" "light" } { "classname" "light" "origin" "816 208 368" "light" "200" } { "classname" "light" "origin" "800 24 368" "light" "200" } { "classname" "light" "origin" "800 376 385" "light" "150" } { "light" "150" "origin" "1400 400 385" "classname" "light" } { "classname" "path_corner" "origin" "1104 336 300" "target" "t126" "targetname" "t127" } { "origin" "1104 24 300" "classname" "path_corner" "targetname" "t126" "target" "t127" } { "classname" "monster_army" "origin" "1104 424 316" "angle" "270" "target" "t127" } { "targetname" "t128" "origin" "1392 240 308" "classname" "info_null" } { "light" "300" "target" "t128" "origin" "1392 240 376" "classname" "light" } { "targetname" "t129" "angle" "0" "origin" "552 -128 320" "classname" "monster_army" } { "target" "t129" "classname" "trigger_once" "model" "*45" } { "sounds" "1" "classname" "trigger_secret" "model" "*46" } { "sounds" "1" "classname" "trigger_secret" "model" "*47" } { "classname" "light" "origin" "1104 24 536" "light" "350" } { "spawnflags" "1" "classname" "func_door_secret" "angle" "270" "model" "*48" } { "light" "200" "origin" "1680 1552 320" "classname" "light" } { "classname" "light" "origin" "1312 1552 320" "light" "200" } { "classname" "item_spikes" "origin" "1480 1104 68" "spawnflags" "1" } { "classname" "item_spikes" "origin" "1760 -568 256" "spawnflags" "1" } { "classname" "item_spikes" "origin" "1232 -1200 416" } { "message" "This door is opened elsewhere..." "classname" "func_door" "sounds" "3" "angle" "180" "wait" "-1" "targetname" "t122" "speed" "35" "spawnflags" "2048" "model" "*49" } { "classname" "func_door" "angle" "0" "wait" "-1" "speed" "30" "spawnflags" "2048" "model" "*50" } { "classname" "light" "origin" "1496 1600 296" "light" "150 " } { "light" "150" "origin" "1568 1664 296" "classname" "light" } { "classname" "light" "origin" "1424 1664 296" "light" "150" } { "classname" "light" "origin" "1328 1424 296" "light" "200" } { "light" "250" "origin" "1696 1416 296" "classname" "light" } { "classname" "monster_army" "origin" "1592 1296 200" "angle" "270" } { "spawnflags" "768" "classname" "monster_demon1" "origin" "-96 576 320" "angle" "270" "targetname" "t73" "target" "t143" } { "classname" "path_corner" "origin" "1392 416 304" "targetname" "t131" "target" "t130" "spawnflags" "768" } { "origin" "1392 296 304" "classname" "path_corner" "targetname" "t130" "target" "t131" "spawnflags" "768" } { "classname" "monster_army" "origin" "1392 352 320" "angle" "270" "target" "t130" "spawnflags" "768" } { "target" "t132" "targetname" "t133" "origin" "296 -328 304" "classname" "path_corner" } { "target" "t133" "targetname" "t132" "classname" "path_corner" "origin" "472 -416 304" } { "spawnflags" "1" "target" "t132" "angle" "90" "origin" "472 -456 320" "classname" "monster_army" } { "spawnflags" "1" "targetname" "t89" "angle" "135" "origin" "1712 -784 376" "classname" "monster_army" } { "target" "t135" "spawnflags" "256" "targetname" "t134" "origin" "400 -1128 416" "classname" "path_corner" } { "target" "t134" "spawnflags" "256" "targetname" "t135" "classname" "path_corner" "origin" "400 -1248 416" } { "target" "t134" "spawnflags" "257" "angle" "90" "origin" "408 -1208 432" "classname" "monster_army" } { "targetname" "t101" "angle" "90" "origin" "-288 -24 488" "classname" "monster_army" "spawnflags" "768" } { "spawnflags" "768" "targetname" "t101" "classname" "monster_army" "origin" "136 -128 488" "angle" "90" } { "spawnflags" "1792" "origin" "-264 -24 464" "classname" "item_rockets" } { "spawnflags" "2048" "origin" "-240 -8 464" "classname" "item_spikes" } { "classname" "monster_ogre" "origin" "-304 -304 488" "angle" "225" "spawnflags" "769" } { "classname" "func_wall" "spawnflags" "768" "model" "*51" } { "classname" "trap_spikeshooter" "origin" "2048 -48 332" "angle" "270" "spawnflags" "769" "targetname" "t121" } { "origin" "2048 -476 332" "classname" "info_null" "targetname" "t136" } { "style" "32" "origin" "2048 -456 336" "classname" "light" "light" "800" "spawnflags" "1" "target" "t136" "targetname" "t137" } { "style" "32" "classname" "trigger_once" "spawnflags" "768" "target" "t137" "model" "*52" } { "classname" "monster_wizard" "origin" "672 328 384" "angle" "180" "spawnflags" "768" "targetname" "t138" } { "classname" "trigger_once" "target" "t138" "model" "*53" } { "style" "32" "classname" "light" "origin" "2004 -52 332" "light" "100" "spawnflags" "1" "targetname" "t137" } { "classname" "item_shells" "origin" "1416 224 300" "spawnflags" "768" } { "classname" "path_corner" "origin" "-344 136 304" "targetname" "t139" "target" "t140" "spawnflags" "768" } { "origin" "168 128 304" "classname" "path_corner" "target" "t139" "targetname" "t140" "spawnflags" "768" } { "classname" "monster_ogre" "origin" "-400 168 320" "spawnflags" "768" "target" "t139" } { "classname" "trap_spikeshooter" "origin" "2120 -256 332" "angle" "180" "spawnflags" "769" "targetname" "t121" } { "classname" "trap_spikeshooter" "origin" "1944 -456 332" "targetname" "t121" "angle" "90" "spawnflags" "769" } { "classname" "item_spikes" "origin" "-336 -80 470" "spawnflags" "768" } { "targetname" "t143" "classname" "trigger_teleport" "target" "t142" "spawnflags" "2" "model" "*54" } { "targetname" "t143" "classname" "trigger_teleport" "target" "t141" "spawnflags" "2" "model" "*55" } { "classname" "monster_demon1" "origin" "32 840 359" "angle" "270" "targetname" "t143" "spawnflags" "768" } { "angle" "270" "origin" "-192 840 359" "classname" "monster_demon1" "targetname" "t143" "spawnflags" "768" } { "classname" "info_teleport_destination" "origin" "80 216 303" "angle" "270" "targetname" "t141" } { "angle" "270" "origin" "-264 224 303" "classname" "info_teleport_destination" "targetname" "t142" } { "wait" "-1" "target" "t53" "health" "1" "classname" "func_button" "model" "*56" } { "spawnflags" "768" "angle" "270" "origin" "1408 1296 200" "classname" "monster_army" } { "classname" "item_shells" "origin" "772 -856 420" "spawnflags" "768" } { "spawnflags" "1792" "origin" "1248 -1128 420" "classname" "weapon_grenadelauncher" } { "spawnflags" "1793" "origin" "864 -312 440" "classname" "item_rockets" } { "classname" "trigger_once" "message" "Pass through the arch to exit..." "model" "*57" } { "mangle" "20 300 0" "classname" "info_intermission" "origin" "-224 424 512" } { "mangle" "20 45 0" "origin" "1048 -744 488" "classname" "info_intermission" } { "mangle" "20 270 0" "origin" "1104 424 528" "classname" "info_intermission" } { "mangle" "20 45 0" "origin" "1240 984 416" "classname" "info_intermission" } { "sounds" "1" "speed" "20" "classname" "func_button" "angle" "0" "wait" "-1" "target" "t144" "model" "*58" } { "classname" "light" "origin" "400 -1392 480" "light" "150" } { "classname" "func_door" "angle" "-2" "wait" "-1" "speed" "20" "sounds" "1" "targetname" "t144" "model" "*59" } { "classname" "trigger_secret" "model" "*60" } { "classname" "item_artifact_super_damage" "origin" "400 -1360 432" } { "classname" "item_spikes" "origin" "808 -632 192" "spawnflags" "2049" } { "classname" "item_health" "origin" "924 -632 192" "spawnflags" "2048" } { "classname" "weapon_supernailgun" "origin" "880 -616 192" "spawnflags" "1792" } { "classname" "ambient_drip" "origin" "842 978 344" } { "classname" "ambient_drip" "origin" "546 330 400" } { "classname" "info_player_coop" "origin" "1608 1664 264" "angle" "270" } { "angle" "270" "origin" "1392 1664 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "1496 1560 264" "angle" "270" } { "spawnflags" "256" "angle" "270" "origin" "232 -176 320" "classname" "monster_ogre" } { "spawnflags" "1280" "angle" "225" "origin" "-368 -312 480" "classname" "monster_knight" } { "spawnflags" "1792" "classname" "func_wall" "model" "*61" } { "origin" "1810 274 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1802 -102 200" } { "origin" "2050 -214 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "2002 -390 200" } { "origin" "1738 -398 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1346 -398 200" } { "origin" "1138 -542 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "882 -494 200" } { "classname" "ambient_swamp1" "origin" "1722 1090 176" } { "origin" "1242 1090 176" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "1106 642 192" } { "origin" "1346 242 192" "classname" "ambient_swamp2" } { "classname" "ambient_swamp1" "origin" "866 210 192" } { "classname" "ambient_swamp1" "origin" "1802 90 192" } { "origin" "1546 -398 192" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "2042 -310 192" } { "origin" "1178 -398 192" "classname" "ambient_swamp2" } { "classname" "ambient_swamp2" "origin" "1202 -678 192" } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e2m3.ent.orig����������������������������������������������������0000644�0000000�0000000�00000113446�12403131422�020000� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "classname" "worldspawn" "wad" "gfx/jr_med.wad" "worldtype" "0" "sounds" "9" "message" "the Crypt of Decay" } { "classname" "light" "origin" "192 -648 128" } { "classname" "info_player_start" "origin" "688 -1600 -312" "angle" "180" } { "classname" "light_flame_large_yellow" "origin" "650 -438 4" } { "origin" "386 -438 4" "classname" "light_flame_large_yellow" } { "origin" "66 -886 4" "classname" "light_flame_large_yellow" } { "origin" "322 -886 4" "classname" "light_flame_large_yellow" } { "light" "250" "origin" "192 -1408 288" "classname" "light" } { "light" "250" "classname" "light" "origin" "192 -1088 288" } { "light" "250" "origin" "112 -1248 272" "classname" "light" } { "light" "250" "classname" "light" "origin" "272 -1248 272" } { "light" "200" "origin" "192 -1056 32" "classname" "light" } { "light" "150" "origin" "192 -1248 24" "classname" "light" } { "origin" "194 -1462 108" "classname" "light_flame_large_yellow" } { "origin" "194 -1030 164" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "192 -1440 32" "classname" "light" } { "sounds" "2" "classname" "func_plat" "spawnflags" "1" "model" "*1" } { "origin" "226 -1670 -212" "classname" "light_flame_large_yellow" } { "light" "150" "origin" "88 -1552 -184" "classname" "light" } { "origin" "-22 -1374 -212" "classname" "light_flame_large_yellow" } { "light" "150" "origin" "328 -1256 -184" "classname" "light" } { "light" "150" "classname" "light" "origin" "56 -1256 -184" } { "classname" "light" "origin" "248 -1480 -184" "light" "150" } { "light" "250" "origin" "552 -1608 -72" "classname" "light" } { "light" "150" "origin" "432 -1656 -224" "classname" "light" } { "light" "150" "origin" "432 -1496 -224" "classname" "light" } { "light" "100" "origin" "192 -1248 -40" "classname" "light" } { "origin" "10 -438 4" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-254 -438 4" } { "light" "150" "origin" "192 -704 -136" "classname" "light" } { "light" "250" "origin" "192 -512 -136" "classname" "light" } { "classname" "light" "origin" "416 -512 -136" "light" "150" } { "light" "150" "origin" "-32 -512 -136" "classname" "light" } { "classname" "light" "origin" "-208 -512 -136" "light" "150" } { "light" "150" "origin" "592 -512 -136" "classname" "light" } { "classname" "light" "origin" "192 -840 -136" "light" "150" } { "light" "150" "origin" "-352 -672 -168" "classname" "light" } { "classname" "light" "origin" "-320 -832 -168" "light" "150" } { "light" "150" "origin" "-320 -512 -168" "classname" "light" } { "classname" "light" "origin" "696 -512 -168" "light" "150" } { "light" "150" "origin" "736 -672 -168" "classname" "light" } { "classname" "light" "origin" "704 -832 -168" "light" "150" } { "light" "150" "origin" "512 -864 -168" "classname" "light" } { "classname" "light" "origin" "-128 -864 -168" "light" "150" } { "light" "200" "origin" "-128 -320 8" "classname" "light" } { "classname" "light" "origin" "512 -320 8" "light" "200" } { "origin" "384 -24 32" "classname" "light" } { "classname" "light" "origin" "0 -24 32" } { "light" "200" "origin" "416 -192 -8" "classname" "light" } { "classname" "light" "origin" "-32 -192 -8" "light" "200" } { "light" "200" "origin" "840 48 72" "classname" "light" } { "light" "150" "origin" "576 -24 -56" "classname" "light" } { "light" "200" "origin" "624 -24 72" "classname" "light" } { "origin" "1002 354 -60" "classname" "light_flame_large_yellow" } { "light" "100" "origin" "1000 352 -128" "classname" "light" } { "classname" "light" "origin" "736 8 72" "light" "200" } { "light" "200" "origin" "936 88 72" "classname" "light" } { "light" "150" "origin" "688 -8 -32" "classname" "light" } { "classname" "light" "origin" "784 24 -104" "light" "150" } { "light" "150" "origin" "888 72 -32" "classname" "light" } { "light" "200" "origin" "872 208 -56" "classname" "light" } { "classname" "light" "origin" "872 400 -56" "light" "200" } { "light" "200" "origin" "872 592 -56" "classname" "light" } { "classname" "light" "origin" "744 568 88" "light" "150" } { "light" "150" "origin" "744 648 88" "classname" "light" } { "classname" "light" "origin" "704 608 -80" "light" "150" } { "origin" "866 730 -60" "classname" "light_flame_large_yellow" } { "classname" "light" "origin" "864 728 -128" "light" "100" } { "sounds" "3" "wait" "-1" "targetname" "t8" "spawnflags" "2049" "angle" "0" "classname" "func_door" "model" "*2" } { "spawnflags" "2048" "angle" "90" "target" "t8" "classname" "func_button" "wait" "-1" "model" "*3" } { "origin" "520 608 -64" "classname" "light" } { "light" "400" "origin" "192 608 -24" "classname" "light" } { "sounds" "1" "wait" "-1" "angle" "270" "spawnflags" "2058" "classname" "func_door_secret" "targetname" "t9" "model" "*4" } { "light" "150" "origin" "1064 640 -112" "classname" "light" } { "targetname" "t9" "angle" "180" "origin" "1024 640 -152" "classname" "monster_zombie" } { "targetname" "t9" "angle" "180" "origin" "1120 672 -152" "classname" "monster_zombie" } { "targetname" "t9" "angle" "180" "origin" "1088 600 -152" "classname" "monster_zombie" } { "origin" "976 336 -176" "classname" "item_health" } { "light" "150" "origin" "192 608 -104" "classname" "light" } { "origin" "192 288 -64" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "66 106 4" "light" "200" } { "light" "200" "origin" "-30 106 4" "classname" "light_flame_large_yellow" } { "classname" "light" "origin" "504 120 -248" "light" "200" } { "light" "200" "origin" "704 224 -248" "classname" "light" } { "classname" "light" "origin" "704 472 -248" "light" "200" } { "light" "200" "origin" "304 112 -248" "classname" "light" } { "classname" "light" "origin" "80 112 -248" "light" "200" } { "light" "200" "origin" "720 608 -248" "classname" "light" } { "spawnflags" "2048" "sounds" "1" "wait" "-1" "targetname" "t3" "classname" "func_door" "angle" "90" "model" "*5" } { "spawnflags" "2048" "wait" "-1" "angle" "270" "classname" "func_door" "message" "This door opens nearby..." "model" "*6" } { "spawnflags" "2048" "target" "t3" "wait" "-1" "classname" "func_button" "angle" "180" "model" "*7" } { "light" "250" "origin" "-448 184 0" "classname" "light" } { "light" "150" "origin" "-552 280 -224" "classname" "light" } { "classname" "light" "origin" "-392 280 -224" "light" "150" } { "light" "150" "origin" "-416 -32 104" "classname" "light" } { "classname" "light" "origin" "-320 -32 104" "light" "150" } { "light" "150" "origin" "-224 -32 104" "classname" "light" } { "light" "250" "origin" "-352 -32 -32" "classname" "light" } { "light" "200" "origin" "-1160 88 -248" "classname" "light" } { "light" "200" "origin" "-1048 88 -32" "classname" "light" } { "light" "200" "classname" "light" "origin" "-1160 224 -32" } { "origin" "-742 658 -44" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-926 658 -44" } { "light" "200" "origin" "-736 632 -96" "classname" "light" } { "classname" "light" "origin" "-928 632 -96" "light" "200" } { "light" "150" "origin" "-600 104 -248" "classname" "light" } { "classname" "light" "origin" "-696 424 -248" "light" "150" } { "light" "150" "origin" "-1152 408 -248" "classname" "light" } { "classname" "light" "origin" "-944 432 -248" "light" "150" } { "light" "150" "origin" "-856 64 -248" "classname" "light" } { "classname" "light" "origin" "-160 152 -248" "light" "150" } { "light" "150" "origin" "-160 448 -248" "classname" "light" } { "classname" "light" "origin" "-328 464 -248" "light" "150" } { "light" "150" "origin" "-256 176 -248" "classname" "light" } { "origin" "-574 410 -172" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-470 410 -172" } { "target" "t4" "classname" "trigger_teleport" "model" "*8" } { "light" "200" "style" "2" "origin" "-760 576 -216" "classname" "light" } { "targetname" "t4" "angle" "180" "origin" "120 -32 -112" "classname" "info_teleport_destination" } { "light" "200" "origin" "-264 384 112" "classname" "light" } { "classname" "light" "origin" "-264 288 112" "light" "200" } { "light" "200" "origin" "-264 192 112" "classname" "light" } { "classname" "light" "origin" "-264 480 112" "light" "200" } { "light" "250" "origin" "-264 304 -56" "classname" "light" } { "classname" "light" "origin" "-520 424 0" "light" "250" } { "light" "200" "origin" "-1120 608 72" "classname" "light" } { "classname" "light" "origin" "-1024 584 72" "light" "200" } { "light" "200" "origin" "-928 584 72" "classname" "light" } { "classname" "light" "origin" "-832 584 72" "light" "200" } { "light" "200" "origin" "-544 584 72" "classname" "light" } { "classname" "light" "origin" "-640 584 72" "light" "200" } { "light" "150" "origin" "-480 768 56" "classname" "light" } { "classname" "light" "origin" "-384 768 56" "light" "150" } { "classname" "light" "origin" "-712 120 -32" "light" "200" } { "sounds" "3" "wait" "-1" "targetname" "t5" "spawnflags" "2049" "angle" "180" "classname" "func_door" "model" "*9" } { "spawnflags" "2048" "angle" "270" "target" "t5" "wait" "-1" "classname" "func_button" "model" "*10" } { "style" "32" "targetname" "t5" "light" "200" "origin" "-352 552 -56" "classname" "light" } { "light" "150" "origin" "-432 768 -56" "classname" "light" } { "light" "150" "origin" "-520 680 -56" "classname" "light" } { "spawnflags" "2048" "sounds" "3" "targetname" "t5" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*11" } { "sounds" "3" "targetname" "t5" "spawnflags" "2049" "wait" "-1" "angle" "90" "classname" "func_door" "model" "*12" } { "origin" "-72 848 -56" "classname" "light" } { "origin" "-120 600 -8" "classname" "light" } { "classname" "light" "origin" "192 904 -8" } { "light" "200" "origin" "192 888 -248" "classname" "light" } { "classname" "light" "origin" "-104 600 -248" "light" "200" } { "light" "200" "origin" "376 984 -120" "classname" "light" } { "classname" "light" "origin" "504 760 -120" "light" "200" } { "light" "200" "origin" "-32 608 200" "classname" "light" } { "spawnflags" "2048" "sounds" "3" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*13" } { "origin" "-16 1456 16" "classname" "light" } { "light" "200" "origin" "384 1248 -56" "classname" "light" } { "classname" "light" "origin" "384 1440 -56" "light" "200" } { "light" "150" "origin" "256 1440 -56" "classname" "light" } { "classname" "light" "origin" "192 1248 -56" "light" "200" } { "light" "200" "origin" "384 1344 -88" "classname" "light" } { "classname" "light" "origin" "192 1152 -88" "light" "200" } { "classname" "light" "origin" "8 1456 -120" "light" "200" } { "spawnflags" "2048" "sounds" "1" "classname" "item_key2" "origin" "-16 1456 -152" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "model" "*14" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "model" "*15" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "spawnflags" "2048" "model" "*16" } { "classname" "trigger_once" "target" "t6" "model" "*17" } { "classname" "light" "origin" "-192 1456 -136" "light" "80" } { "classname" "light" "origin" "-16 1280 -136" "light" "80" } { "spawnflags" "768" "classname" "monster_hell_knight" "origin" "-16 1280 -168" "angle" "90" "targetname" "t6" } { "spawnflags" "256" "angle" "270" "origin" "-16 1632 -168" "classname" "monster_hell_knight" "targetname" "t6" } { "classname" "monster_hell_knight" "origin" "-192 1456 -168" "angle" "0" "targetname" "t6" } { "classname" "light" "origin" "152 1440 -56" "light" "150" } { "classname" "item_shells" "origin" "-104 1512 -192" "spawnflags" "1" } { "wait" "-1" "classname" "func_door" "angle" "0" "spawnflags" "2056" "model" "*18" } { "wait" "-1" "classname" "func_door" "angle" "180" "spawnflags" "2056" "model" "*19" } { "classname" "light" "origin" "-1120 832 -48" "light" "250" } { "classname" "light" "origin" "-1120 976 -24" "light" "250" } { "classname" "light" "origin" "-1240 1296 216" "light" "200" } { "light" "200" "origin" "-1240 1416 216" "classname" "light" } { "classname" "light" "origin" "-1240 1176 216" "light" "200" } { "classname" "light" "origin" "-712 1416 216" "light" "200" } { "light" "200" "origin" "-712 1296 216" "classname" "light" } { "classname" "light" "origin" "-712 1176 216" "light" "200" } { "light" "200" "origin" "-856 1296 216" "classname" "light" } { "classname" "light" "origin" "-1096 1296 216" "light" "200" } { "light" "200" "origin" "-976 1296 216" "classname" "light" } { "classname" "light_flame_small_white" "origin" "-1318 1514 -8" } { "origin" "-1318 1514 64" "classname" "light_flame_small_white" } { "classname" "light_flame_small_white" "origin" "-1318 1514 144" } { "origin" "-634 1078 -8" "classname" "light_flame_small_white" } { "classname" "light_flame_small_white" "origin" "-634 1078 64" } { "origin" "-634 1078 144" "classname" "light_flame_small_white" } { "classname" "func_plat" "spawnflags" "1" "model" "*20" } { "classname" "light" "origin" "-320 1536 184" "light" "250" } { "classname" "light" "origin" "-376 1312 120" "light" "250" } { "classname" "light" "origin" "-16 1536 184" "light" "200" } { "light" "200" "origin" "-560 1312 56" "classname" "light" } { "classname" "light" "origin" "24 1120 216" "light" "150" } { "classname" "light" "origin" "192 608 176" "light" "200" } { "wait" "-1" "classname" "func_door" "angle" "90" "spawnflags" "2049" "targetname" "t7" "sounds" "1" "model" "*21" } { "light" "150" "origin" "400 1104 224" "classname" "light" } { "light" "150" "origin" "-200 1056 224" "classname" "light" } { "light" "200" "origin" "192 960 224" "classname" "light" } { "light" "200" "origin" "192 784 224" "classname" "light" } { "classname" "light" "origin" "672 264 184" "light" "200" } { "light" "200" "origin" "384 184 184" "classname" "light" } { "classname" "light" "origin" "512 256 8" "light" "200" } { "classname" "light" "origin" "8 184 200" "light" "200" } { "classname" "light" "origin" "584 744 200" "light" "200" } { "classname" "light" "origin" "0 432 200" "light" "200" } { "classname" "trigger_once" "targetname" "t8" "target" "t9" "delay" "10" "model" "*22" } { "classname" "light" "origin" "192 -72 216" "light" "250" } { "classname" "light" "origin" "360 -168 360" "light" "200" } { "classname" "light" "origin" "296 -168 360" "light" "200" } { "origin" "472 -168 368" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "408 -168 360" } { "classname" "light" "origin" "384 -168 248" "light" "200" } { "classname" "light" "origin" "936 -304 328" "light" "200" } { "light" "200" "origin" "1000 -232 360" "classname" "light" } { "classname" "light" "origin" "864 -232 360" "light" "200" } { "light" "200" "origin" "864 -368 360" "classname" "light" } { "classname" "light" "origin" "1000 -368 360" "light" "200" } { "classname" "light" "origin" "736 -248 280" "light" "200" } { "light" "200" "origin" "552 -216 280" "classname" "light" } { "classname" "light" "origin" "16 144 -32" "light" "200" } { "classname" "light" "origin" "0 432 -136" "light" "200" } { "classname" "light" "origin" "192 384 184" "light" "200" } { "light" "200" "origin" "192 192 184" "classname" "light" } { "spawnflags" "2048" "classname" "func_button" "wait" "-1" "target" "t7" "model" "*23" } { "style" "33" "targetname" "t7" "classname" "light" "origin" "176 1152 200" "target" "t10" } { "classname" "info_null" "origin" "292 1152 180" "targetname" "t10" } { "classname" "light" "origin" "192 1224 200" "light" "150" } { "light" "150" "origin" "192 1376 200" "classname" "light" } { "classname" "light" "origin" "192 1536 200" "light" "200" } { "light" "150" "origin" "192 1080 200" "classname" "light" } { "classname" "weapon_nailgun" "origin" "184 -1520 -272" } { "classname" "func_button" "target" "t11" "angle" "-1" "targetname" "t12" "lip" "4" "wait" "0.1" "speed" "300" "health" "1" "model" "*24" } { "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t11" "wait" "10" "model" "*25" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "8" "targetname" "t11" "model" "*26" } { "classname" "light" "origin" "1248 -288 312" "light" "150" } { "light" "200" "origin" "1176 -400 352" "classname" "light" } { "classname" "item_health" "origin" "1336 -536 256" "spawnflags" "2" } { "classname" "light" "origin" "1320 -488 352" "light" "200" } { "classname" "trigger_multiple" "target" "t11" "wait" "10" "model" "*27" } { "classname" "item_armor1" "origin" "192 -592 -64" } { "classname" "item_shells" "origin" "176 592 -160" "spawnflags" "1" } { "classname" "weapon_nailgun" "origin" "-80 1456 -192" "spawnflags" "1792" } { "classname" "weapon_rocketlauncher" "origin" "56 1144 128" "spawnflags" "1792" } { "classname" "weapon_grenadelauncher" "origin" "-736 608 -280" "spawnflags" "1792" } { "classname" "item_spikes" "origin" "1120 -384 256" "spawnflags" "1" } { "classname" "item_rockets" "origin" "840 -432 192" "spawnflags" "1" } { "classname" "item_spikes" "origin" "-456 312 -80" } { "classname" "monster_zombie" "origin" "-1152 96 -88" "spawnflags" "256" "target" "t36" } { "origin" "-1120 32 -88" "classname" "monster_zombie" "spawnflags" "768" "target" "t36" } { "classname" "monster_zombie" "origin" "-1192 168 -88" "target" "t36" } { "classname" "monster_shambler" "origin" "-1120 1104 -56" "angle" "270" } { "classname" "monster_hell_knight" "origin" "-336 1312 8" "angle" "180" } { "classname" "monster_ogre" "origin" "-698 1446 -56" "angle" "270" "spawnflags" "256" } { "classname" "monster_hell_knight" "origin" "-888 1128 8" "angle" "90" "spawnflags" "256" } { "classname" "item_health" "origin" "-336 784 -128" } { "origin" "-408 608 -128" "classname" "item_health" } { "classname" "path_corner" "origin" "-1096 584 -120" "targetname" "t13" "target" "t14" } { "origin" "-496 584 -120" "classname" "path_corner" "targetname" "t14" "target" "t13" } { "classname" "monster_demon1" "origin" "-712 576 -104" "angle" "180" "target" "t13" } { "classname" "path_corner" "origin" "-528 472 -96" "targetname" "t15" "target" "t16" } { "origin" "-368 -32 -96" "classname" "path_corner" "target" "t15" "targetname" "t16" } { "classname" "monster_ogre" "origin" "-466 262 -56" "target" "t16" "spawnflags" "256" } { "target" "t22" "targetname" "t21" "origin" "56 -184 -120" "classname" "path_corner" } { "target" "t21" "targetname" "t20" "classname" "path_corner" "origin" "-128 -224 -120" } { "target" "t20" "targetname" "t19" "origin" "-128 -504 -56" "classname" "path_corner" } { "target" "t19" "targetname" "t18" "classname" "path_corner" "origin" "512 -504 -56" } { "target" "t18" "targetname" "t17" "origin" "512 -224 -120" "classname" "path_corner" } { "targetname" "t26" "target" "t17" "classname" "path_corner" "origin" "328 -184 -120" } { "target" "t23" "targetname" "t22" "classname" "path_corner" "origin" "-128 -200 -120" } { "target" "t24" "targetname" "t23" "classname" "path_corner" "origin" "-128 -552 -56" } { "target" "t25" "targetname" "t24" "origin" "512 -552 -56" "classname" "path_corner" } { "target" "t26" "targetname" "t25" "classname" "path_corner" "origin" "512 -200 -120" } { "spawnflags" "256" "target" "t21" "origin" "0 -184 -104" "classname" "monster_hell_knight" } { "spawnflags" "1" "origin" "376 -160 -104" "classname" "monster_hell_knight" } { "spawnflags" "768" "angle" "270" "origin" "190 -706 -40" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "90" "origin" "192 -1408 24" "classname" "monster_hell_knight" } { "origin" "40 -1424 0" "classname" "item_shells" "spawnflags" "1" } { "spawnflags" "1" "origin" "304 -1096 0" "classname" "item_health" } { "origin" "328 -1280 -272" "classname" "item_health" } { "origin" "40 -1256 -272" "classname" "item_spikes" } { "target" "t28" "targetname" "t27" "origin" "864 176 -168" "classname" "path_corner" } { "target" "t27" "targetname" "t28" "classname" "path_corner" "origin" "864 616 -168" } { "target" "t27" "origin" "862 446 -152" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "180" "origin" "526 -26 -104" "classname" "monster_ogre" } { "spawnflags" "256" "angle" "0" "origin" "-72 -24 -104" "classname" "monster_hell_knight" } { "spawnflags" "256" "origin" "-274 -34 -104" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "270" "origin" "-512 760 -104" "classname" "monster_hell_knight" } { "spawnflags" "1793" "origin" "336 1104 128" "classname" "item_rockets" } { "angle" "45" "spawnflags" "256" "origin" "104 256 -136" "classname" "monster_zombie" } { "spawnflags" "769" "angle" "90" "origin" "192 488 -136" "classname" "monster_hell_knight" } { "wait" "1" "speed" "250" "lip" "16" "spawnflags" "5" "targetname" "t29" "dmg" "20" "angle" "180" "classname" "func_door" "model" "*28" } { "wait" "1" "targetname" "t29" "speed" "250" "dmg" "20" "lip" "16" "spawnflags" "5" "classname" "func_door" "sounds" "1" "model" "*29" } { "wait" "2" "target" "t29" "classname" "trigger_multiple" "model" "*30" } { "origin" "506 1762 -124" "classname" "light_torch_small_walltorch" "style" "1" } { "classname" "light_torch_small_walltorch" "origin" "274 2010 -124" } { "light" "200" "origin" "152 1824 -40" "classname" "light" } { "classname" "light" "origin" "288 1824 -40" "light" "200" } { "light" "200" "origin" "288 1696 -40" "classname" "light" } { "classname" "light" "origin" "152 1704 -40" "light" "200" } { "light" "220" "origin" "0 1704 -40" "classname" "light" } { "angle" "180" "classname" "func_door_secret" "targetname" "t35" "spawnflags" "16" "sounds" "1" "model" "*31" } { "spawnflags" "2" "origin" "-16 1816 -192" "classname" "item_health" } { "origin" "432 1672 -320" "classname" "light" "light" "220" } { "spawnflags" "1792" "origin" "-16 1752 -192" "classname" "item_rockets" } { "angle" "270" "origin" "-192 1580 168" "classname" "trap_spikeshooter" "targetname" "t32" } { "spawnflags" "256" "classname" "trap_spikeshooter" "origin" "236 1536 168" "angle" "180" "targetname" "t32" } { "classname" "trap_spikeshooter" "origin" "0 1580 168" "angle" "270" "targetname" "t32" } { "angle" "90" "origin" "-96 1492 168" "classname" "trap_spikeshooter" "targetname" "t32" } { "classname" "trap_spikeshooter" "origin" "148 1376 168" "angle" "0" "targetname" "t33" } { "angle" "180" "origin" "236 1256 168" "classname" "trap_spikeshooter" "targetname" "t33" } { "spawnflags" "256" "classname" "trap_spikeshooter" "origin" "192 1580 168" "angle" "270" "targetname" "t33" } { "spawnflags" "257" "angle" "90" "origin" "192 -16 153" "classname" "monster_hell_knight" } { "spawnflags" "257" "angle" "180" "origin" "864 -248 217" "classname" "monster_shambler" } { "angle" "180" "origin" "464 -184 185" "classname" "monster_hell_knight" } { "classname" "monster_hell_knight" "origin" "192 -176 153" "angle" "90" "spawnflags" "1" "target" "t31" } { "spawnflags" "769" "angle" "90" "origin" "190 1166 153" "classname" "monster_ogre" } { "spawnflags" "2048" "origin" "48 1456 -192" "classname" "weapon_grenadelauncher" } { "spawnflags" "1" "origin" "-96 1376 -192" "classname" "item_rockets" } { "angle" "270" "spawnflags" "768" "classname" "monster_ogre" "origin" "862 662 -152" } { "light" "120" "origin" "192 -352 -264" "classname" "light" } { "spawnflags" "768" "origin" "326 -1490 -248" "classname" "monster_ogre" "angle" "180" "target" "t42" } { "origin" "192 552 128" "classname" "item_health" } { "spawnflags" "1024" "classname" "item_health" "origin" "176 672 128" } { "spawnflags" "1025" "origin" "184 1312 128" "classname" "item_health" } { "classname" "item_health" "origin" "-16 1480 128" "spawnflags" "1025" } { "origin" "672 -328 176" "classname" "item_health" } { "classname" "item_health" "origin" "776 -192 176" } { "origin" "784 312 -176" "classname" "item_shells" } { "spawnflags" "256" "angle" "315" "origin" "-26 1094 152" "classname" "monster_ogre" } { "classname" "monster_ogre" "origin" "406 1094 152" "angle" "225" "spawnflags" "768" } { "spawnflags" "1" "origin" "-200 1128 128" "classname" "item_rockets" } { "origin" "-550 -478 212" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "-550 -166 212" } { "origin" "-214 -326 252" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "-120 -176 192" "classname" "light" } { "classname" "light" "origin" "56 -176 192" "light" "150" } { "origin" "-816 1488 -80" "classname" "item_health" } { "classname" "item_health" "origin" "-752 1488 -80" } { "spawnflags" "1536" "origin" "-688 1488 -80" "classname" "item_health" } { "spawnflags" "1" "origin" "176 1264 -160" "classname" "item_shells" } { "classname" "func_door" "angle" "270" "targetname" "t31" "wait" "-1" "spawnflags" "2048" "model" "*32" } { "wait" "-1" "sounds" "1" "speed" "300" "classname" "func_door" "angle" "90" "model" "*33" } { "speed" "300" "classname" "func_door" "angle" "270" "wait" "-1" "model" "*34" } { "classname" "item_health" "origin" "400 1464 -160" "spawnflags" "1024" } { "classname" "item_health" "origin" "-1136 528 -128" } { "classname" "monster_ogre" "origin" "-370 -218 88" "targetname" "t31" "spawnflags" "1" } { "classname" "monster_hell_knight" "origin" "-64 -176 152" "angle" "0" "spawnflags" "768" "targetname" "t31" } { "classname" "item_health" "origin" "-488 -480 64" } { "classname" "light" "origin" "680 -1600 -160" } { "classname" "item_spikes" "origin" "984 -192 192" "spawnflags" "1" } { "classname" "monster_ogre" "origin" "-490 -410 88" "angle" "45" } { "classname" "trigger_multiple" "target" "t32" "wait" "1" "spawnflags" "1024" "targetname" "t44" "model" "*35" } { "classname" "trigger_multiple" "target" "t33" "wait" "1" "spawnflags" "1024" "model" "*36" } { "classname" "item_rockets" "origin" "-96 272 -384" } { "classname" "weapon_supernailgun" "origin" "-1200 208 -112" "spawnflags" "1792" } { "classname" "func_door_secret" "spawnflags" "2051" "targetname" "t36" "angle" "90" "model" "*37" } { "classname" "light" "origin" "-1288 640 -80" "light" "160" } { "light" "160" "origin" "-1288 128 -80" "classname" "light" } { "classname" "light" "origin" "-1288 264 -80" "light" "160" } { "light" "160" "origin" "-1288 392 -80" "classname" "light" } { "classname" "light" "origin" "-1288 520 -80" "light" "160" } { "classname" "func_door_secret" "targetname" "t36" "angle" "270" "spawnflags" "2049" "model" "*38" } { "classname" "item_armor2" "origin" "1128 600 -176" "spawnflags" "1024" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "11" "targetname" "t34" "model" "*39" } { "classname" "light_torch_small_walltorch" "origin" "-246 -1310 -204" "light" "250" } { "classname" "trigger_once" "target" "t34" "model" "*40" } { "classname" "item_spikes" "origin" "-240 -1288 -312" "spawnflags" "1" } { "spawnflags" "1" "origin" "-240 -1368 -312" "classname" "item_spikes" } { "sounds" "3" "classname" "func_door" "angle" "-2" "spawnflags" "3585" "wait" "90" "targetname" "t6" "model" "*41" } { "sounds" "3" "classname" "func_door" "targetname" "t6" "spawnflags" "3585" "angle" "-2" "wait" "90" "model" "*42" } { "sounds" "3" "classname" "func_door" "angle" "0" "spawnflags" "1537" "targetname" "t6" "wait" "90" "model" "*43" } { "classname" "light_torch_small_walltorch" "origin" "-42 1642 -108" "light" "200" } { "classname" "item_health" "origin" "-72 560 -384" } { "origin" "-152 560 -384" "classname" "item_health" } { "targetname" "t31" "spawnflags" "513" "angle" "90" "origin" "848 -376 216" "classname" "monster_hell_knight" } { "targetname" "t31" "spawnflags" "768" "origin" "-512 -248 88" "classname" "monster_shambler" } { "spawnflags" "768" "angle" "180" "origin" "382 1246 -136" "classname" "monster_ogre" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "190 1438 -136" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "640 -1664 -312" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "-400 -240 88" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "-216 1088 152" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "-512 792 -104" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "888 624 -152" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "-96 1456 -168" "angle" "0" } { "spawnflags" "2048" "classname" "func_wall" "model" "*44" } { "spawnflags" "2048" "classname" "func_wall" "model" "*45" } { "classname" "func_plat" "height" "192" "sounds" "2" "model" "*46" } { "classname" "item_health" "origin" "-1184 72 -352" } { "classname" "light" "origin" "-952 1408 80" "light" "200" } { "classname" "light" "origin" "-1120 1176 48" "light" "250" } { "classname" "light" "origin" "-104 288 -344" "light" "200" } { "classname" "light" "origin" "-512 376 -304" "light" "200" } { "classname" "trigger_multiple" "target" "t35" "model" "*47" } { "classname" "light" "origin" "192 -376 -16" "light" "150" } { "classname" "light" "origin" "192 -328 176" "light" "150" } { "classname" "trigger_multiple" "target" "t32" "spawnflags" "768" "wait" "0.5" "model" "*48" } { "classname" "trigger_multiple" "spawnflags" "768" "wait" "0.5" "target" "t33" "targetname" "t44" "model" "*49" } { "origin" "-1176 112 -112" "classname" "item_rockets" } { "origin" "-736 544 -280" "classname" "item_armorInv" } { "classname" "func_button" "angle" "180" "target" "t36" "model" "*50" } { "classname" "info_null" "origin" "-1332 1116 -36" "targetname" "t37" } { "classname" "light" "origin" "-1296 1120 -32" "target" "t37" "angle" "60" } { "spawnflags" "2048" "classname" "func_wall" "model" "*51" } { "spawnflags" "2048" "classname" "func_wall" "model" "*52" } { "classname" "light" "origin" "192 -152 -344" "light" "160" } { "classname" "light" "origin" "192 32 -344" "light" "160" } { "classname" "light" "origin" "32 168 -344" "light" "140" } { "light" "160" "origin" "-16 408 -344" "classname" "light" } { "classname" "light" "origin" "192 368 -344" "light" "140" } { "light" "140" "origin" "448 368 -344" "classname" "light" } { "classname" "light" "origin" "528 592 -344" "light" "200" } { "light" "200" "origin" "408 808 -344" "classname" "light" } { "classname" "light" "origin" "192 832 -344" "light" "200" } { "light" "200" "origin" "-40 728 -344" "classname" "light" } { "classname" "light" "origin" "-168 632 -344" "light" "200" } { "light" "200" "origin" "-160 976 -344" "classname" "light" } { "classname" "light" "origin" "592 456 -344" "light" "200" } { "classname" "light" "origin" "192 352 -232" "light" "200" } { "light" "200" "origin" "32 264 -232" "classname" "light" } { "classname" "light" "origin" "-184 432 -336" "light" "160" } { "light" "160" "origin" "-192 144 -336" "classname" "light" } { "classname" "light" "origin" "-776 280 -312" "light" "200" } { "light" "200" "origin" "-864 432 -312" "classname" "light" } { "classname" "light" "origin" "-1096 432 -312" "light" "200" } { "light" "200" "origin" "-1168 272 -312" "classname" "light" } { "classname" "light" "origin" "-944 64 -312" "light" "200" } { "light" "200" "origin" "-664 136 -312" "classname" "light" } { "light" "200" "origin" "-1112 592 -96" "classname" "light" } { "classname" "light" "origin" "-1040 1256 -32" "light" "150" } { "light" "200" "origin" "-880 1128 80" "classname" "light" } { "classname" "light" "origin" "-712 1400 -16" "light" "200" } { "classname" "light" "origin" "104 -600 -224" "light" "200" } { "light" "200" "origin" "280 -600 -224" "classname" "light" } { "classname" "trigger_changelevel" "map" "e2m4" "model" "*53" } { "light" "160" "origin" "-312 808 -72" "classname" "light" } { "light" "200" "origin" "192 1776 -312" "classname" "light" } { "classname" "light" "origin" "-392 568 -56" "light" "160" } { "classname" "light" "origin" "-1224 1504 8" "light" "170" } { "light" "170" "origin" "-1304 1392 8" "classname" "light" } { "classname" "light" "origin" "-640 1168 -8" "light" "170" } { "light" "160" "origin" "352 -1248 56" "classname" "light" } { "classname" "light" "origin" "40 -1248 56" "light" "160" } { "light" "160" "origin" "192 -1216 -176" "classname" "light" } { "classname" "light" "origin" "24 -1376 -232" "light" "160" } { "light" "160" "origin" "224 -1624 -232" "classname" "light" } { "classname" "light" "origin" "368 -1392 -232" "light" "160" } { "classname" "light" "origin" "8 -464 -40" "light" "140" } { "light" "140" "origin" "384 -464 -40" "classname" "light" } { "classname" "light" "origin" "-544 800 -56" "light" "140" } { "classname" "trigger_secret" "model" "*54" } { "classname" "trigger_secret" "model" "*55" } { "light" "200" "origin" "760 1856 -40" "classname" "light" } { "classname" "light" "origin" "760 1664 -40" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "538 1762 -124" "style" "1" "light" "200" } { "style" "1" "classname" "light_torch_small_walltorch" "origin" "850 1930 -124" "light" "200" } { "origin" "850 1618 -124" "classname" "light_torch_small_walltorch" "style" "1" "light" "200" } { "classname" "light" "origin" "912 1856 -40" "light" "200" } { "light" "200" "origin" "912 1664 -40" "classname" "light" } { "light" "200" "origin" "1064 1776 -172" "classname" "light" } { "light" "200" "origin" "1080 1856 -40" "classname" "light" } { "classname" "light" "origin" "1080 1664 -40" "light" "200" } { "classname" "light" "origin" "1176 1776 -172" "light" "200" } { "light" "170" "origin" "672 1768 -296" "classname" "light" } { "target" "t38" "classname" "trigger_teleport" "model" "*56" } { "targetname" "t38" "origin" "1144 1776 -88" "classname" "info_teleport_destination" } { "map" "e2m7" "classname" "trigger_changelevel" "model" "*57" } { "light" "160" "origin" "840 1768 -200" "classname" "light" } { "light" "140" "origin" "408 608 -344" "classname" "light" } { "classname" "item_spikes" "origin" "-16 240 -160" "spawnflags" "2048" } { "classname" "weapon_supernailgun" "origin" "-1256 1448 -80" } { "origin" "432 1160 152" "classname" "item_artifact_super_damage" } { "message" "The portal lies beyond..." "targetname" "t40" "wait" "-1" "speed" "20" "sounds" "4" "angle" "-2" "classname" "func_door" "model" "*58" } { "origin" "432 1672 -368" "classname" "item_armor2" } { "target" "t39" "sounds" "1" "wait" "-1" "classname" "func_button" "model" "*59" } { "message" "The underwater barrier is lowered..." "target" "t40" "targetname" "t39" "spawnflags" "1" "classname" "trigger_once" "model" "*60" } { "classname" "trigger_secret" "model" "*61" } { "light" "200" "origin" "-128 -704 -224" "classname" "light" } { "classname" "light" "origin" "512 -704 -224" "light" "200" } { "light" "200" "origin" "192 -832 -224" "classname" "light" } { "mangle" "20 240 0" "origin" "400 1048 240" "classname" "info_intermission" } { "mangle" "20 145 0" "origin" "-160 144 64" "classname" "info_intermission" } { "mangle" "-20 45 0" "origin" "-320 -824 -144" "classname" "info_intermission" } { "classname" "func_wall" "spawnflags" "1792" "model" "*62" } { "classname" "item_artifact_super_damage" "origin" "928 1768 -240" "spawnflags" "1792" } { "classname" "light" "origin" "8 1800 -120" "light" "220" } { "classname" "weapon_lightning" "origin" "1216 1784 -264" "spawnflags" "1792" } { "classname" "item_cells" "origin" "880 1648 -264" "spawnflags" "1793" } { "spawnflags" "1793" "origin" "880 1864 -264" "classname" "item_cells" } { "spawnflags" "1792" "classname" "func_wall" "model" "*63" } { "spawnflags" "1792" "classname" "func_wall" "model" "*64" } { "spawnflags" "1792" "classname" "func_wall" "model" "*65" } { "classname" "info_player_coop" "origin" "664 -1520 -312" "angle" "180" } { "angle" "180" "origin" "592 -1600 -312" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "680 -1712 -312" "angle" "180" } { "classname" "air_bubbles" "origin" "720 1384 -320" } { "classname" "light" "origin" "680 1376 -312" } { "classname" "func_door_secret" "angle" "180" "spawnflags" "2" "targetname" "t41" "model" "*66" } { "classname" "trigger_multiple" "target" "t41" "model" "*67" } { "origin" "688 1176 -312" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "480 1408 -312" } { "origin" "448 1552 -312" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "840 1080 -312" } { "origin" "840 1080 -160" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "840 1080 0" } { "classname" "light" "origin" "840 1080 232" "light" "200" } { "classname" "item_artifact_envirosuit" "origin" "576 1440 -344" } { "classname" "item_artifact_invulnerability" "origin" "544 1248 -344" } { "light" "200" "origin" "840 936 232" "classname" "light" } { "classname" "light" "origin" "840 760 232" "light" "150" } { "light" "120" "origin" "808 600 232" "classname" "light" } { "classname" "item_health" "origin" "824 960 152" } { "origin" "848 880 152" "classname" "item_health" } { "classname" "item_health" "origin" "808 768 152" } { "classname" "trigger_multiple" "message" "Welcome to the Well of Wishes!" "wait" "5" "sounds" "1" "model" "*68" } { "classname" "trigger_multiple" "sounds" "1" "wait" "3" "message" "The Dopefish Lives!" "model" "*69" } { "classname" "func_wall" "spawnflags" "1792" "model" "*70" } { "classname" "trigger_secret" "model" "*71" } { "spawnflags" "1" "origin" "-1312 1392 -80" "classname" "item_spikes" } { "classname" "func_wall" "spawnflags" "1792" "model" "*72" } { "classname" "light" "origin" "-544 600 -248" "light" "200" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "194 -214 196" "spawnflags" "2048" } { "light" "200" "origin" "352 984 -328" "classname" "light" } { "classname" "light" "origin" "96 976 -328" "light" "200" } { "classname" "light" "origin" "640 776 -336" "light" "200" } { "classname" "func_plat" "spawnflags" "1" "model" "*73" } { "classname" "monster_fish" "origin" "656 352 -336" "spawnflags" "256" } { "spawnflags" "256" "origin" "432 424 -336" "classname" "monster_fish" } { "classname" "monster_fish" "origin" "296 968 -336" "spawnflags" "256" } { "origin" "-48 800 -336" "classname" "monster_fish" } { "classname" "monster_fish" "origin" "-896 248 -312" } { "origin" "-744 328 -312" "classname" "monster_fish" } { "classname" "path_corner" "origin" "272 -1504 -264" "targetname" "t42" "target" "t43" } { "origin" "56 -1352 -264" "classname" "path_corner" "target" "t42" "targetname" "t43" } { "classname" "item_health" "origin" "312 -1336 -272" } { "origin" "544 -1488 -336" "classname" "item_health" } { "classname" "item_health" "origin" "312 1464 -160" } { "origin" "56 1488 -192" "classname" "item_health" } { "classname" "trigger_once" "killtarget" "t44" "spawnflags" "3072" "model" "*74" } { "classname" "item_rockets" "origin" "216 648 120" "spawnflags" "1" } { "classname" "item_shells" "origin" "136 648 120" "spawnflags" "1" } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e1m4.ent���������������������������������������������������������0000644�0000000�0000000�00000125327�12425501423�017050� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "message" "the Grisly Grotto" "worldtype" "0" "classname" "worldspawn" "wad" "gfx/wizard.wad" "sounds" "5" } { "classname" "light" "origin" "464 480 1656" "light" "300" } { "light" "400" "origin" "712 296 1512" "classname" "light" } { "sounds" "3" "angle" "180" "classname" "func_door" "model" "*1" } { "angle" "0" "classname" "func_door" "model" "*2" } { "classname" "light_flame_small_yellow" "origin" "560 -112 1374" } { "origin" "848 -112 1374" "classname" "light_flame_small_yellow" } { "origin" "760 656 1536" "classname" "light" } { "light" "400" "origin" "834 498 1040" "classname" "light" } { "light" "200" "classname" "light" "origin" "944 728 1456" } { "classname" "light_flame_small_yellow" "origin" "1016 80 998" } { "origin" "392 80 998" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "680 1224 516" "light" "200" } { "light" "200" "origin" "704 992 516" "classname" "light" } { "light" "200" "origin" "696 1608 628" "classname" "light" } { "origin" "704 1368 588" "classname" "light" } { "origin" "816 1616 444" "classname" "light" } { "classname" "light" "origin" "712 1728 444" } { "origin" "592 1608 444" "classname" "light" } { "classname" "light" "origin" "624 1096 444" } { "light" "300" "origin" "432 1328 816" "classname" "light" } { "classname" "light" "origin" "696 1112 816" "light" "300" } { "classname" "light" "origin" "704 -80 960" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "818 18 948" "light" "200" } { "origin" "586 18 948" "classname" "light_torch_small_walltorch" "light" "200" } { "light" "200" "origin" "688 496 880" "classname" "light" } { "origin" "489 483 1356" "classname" "light_flame_large_yellow" } { "light" "200" "origin" "704 -120 1360" "classname" "light" } { "classname" "light" "origin" "1216 936 1560" "light" "200" } { "origin" "1294 826 1576" "classname" "light_flame_large_yellow" } { "sounds" "1" "targetname" "t1" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*3" } { "angle" "0" "wait" "-1" "classname" "func_door" "model" "*4" } { "target" "t1" "classname" "trigger_once" "model" "*5" } { "map" "e1m5" "classname" "trigger_changelevel" "model" "*6" } { "wait" "-1" "angle" "0" "classname" "func_door" "speed" "50" "model" "*7" } { "classname" "info_player_start" "origin" "-256 2272 1240" "angle" "270" } { "targetname" "t23" "classname" "func_door" "angle" "180" "wait" "-1" "speed" "50" "sounds" "3" "model" "*8" } { "classname" "light" "origin" "696 704 820" } { "classname" "light" "origin" "704 776 672" "light" "200" } { "classname" "light" "origin" "360 904 520" "light" "200" } { "origin" "704 856 400" "classname" "light" "light" "200" } { "classname" "light" "origin" "944 880 416" "light" "150" } { "origin" "1056 1176 424" "classname" "light" "light" "200" } { "classname" "light" "origin" "1096 1408 360" } { "classname" "light" "origin" "416 1696 360" } { "origin" "328 1368 360" "classname" "light" "light" "200" } { "light" "200 " "classname" "light" "origin" "696 752 896" } { "light" "250" "origin" "798 1850 1024" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "642 1850 1024" "light" "250" } { "light" "200 " "origin" "700 1364 952" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "1094 1494 1064" } { "origin" "324 1104 1064" "classname" "light_flame_large_yellow" } { "light" "200 " "origin" "704 1660 952" "classname" "light" } { "sounds" "3" "classname" "func_door" "angle" "180" "wait" "-1" "targetname" "t2" "model" "*9" } { "sounds" "3" "classname" "func_door" "wait" "-1" "angle" "0" "targetname" "t4" "model" "*10" } { "classname" "trigger_once" "targetname" "t4" "target" "t7" "model" "*11" } { "classname" "trigger_once" "targetname" "t2" "target" "t7" "model" "*12" } { "dmg" "90" "speed" "200" "classname" "func_train" "target" "t5" "targetname" "t8" "model" "*13" } { "classname" "path_corner" "origin" "-359 1528 1316" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "-359 1528 880" "targetname" "t6" "target" "t5" "wait" "-1" } { "classname" "trigger_counter" "targetname" "t7" "target" "t8" "count" "2" "model" "*14" } { "targetname" "t11" "origin" "-96 1640 1256" "classname" "info_null" } { "targetname" "t9" "origin" "-416 1640 1256" "classname" "info_null" } { "light" "400" "target" "t9" "origin" "-396 1640 1256" "classname" "light" } { "light" "400" "target" "t11" "origin" "-116 1640 1256" "classname" "light" } { "classname" "light" "origin" "-328 1564 1532" } { "classname" "light_flame_small_yellow" "origin" "-88 1640 1514" } { "origin" "-424 1640 1514" "classname" "light_flame_small_yellow" } { "origin" "-248 1464 1154" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "-256 1808 1046" } { "light" "200" "origin" "-164 1732 1268" "classname" "light" } { "classname" "light" "origin" "-348 1732 1268" "light" "200" } { "light" "150" "origin" "-248 1500 1056" "classname" "light" } { "light" "150" "origin" "-256 1772 956" "classname" "light" } { "classname" "light" "origin" "-128 1636 920" "light" "150" } { "light" "150" "origin" "-124 1640 920" "classname" "light" } { "classname" "light" "origin" "-172 1524 920" "light" "150" } { "light" "150" "origin" "-284 1516 920" "classname" "light" } { "classname" "light" "origin" "-360 1580 920" "light" "150" } { "light" "75" "origin" "-360 1700 920" "classname" "light" } { "classname" "light" "origin" "72 1632 928" "light" "125" } { "light" "150" "origin" "80 1488 928" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "158 1308 1064" } { "classname" "light" "origin" "-192 1688 1380" "light" "100" } { "light" "100" "origin" "-192 1592 1380" "classname" "light" } { "classname" "light" "origin" "-320 1592 1380" "light" "100" } { "light" "100" "origin" "-320 1688 1380" "classname" "light" } { "classname" "light" "origin" "-384 1640 1452" "light" "125" } { "classname" "light" "origin" "-112 1640 1452" "light" "125" } { "light" "200" "origin" "-248 1504 1336" "classname" "light" } { "classname" "light" "origin" "-128 1640 1336" "light" "200" } { "light" "200" "origin" "-384 1640 1336" "classname" "light" } { "classname" "light" "origin" "696 1608 816" "light" "300" } { "light" "200" "classname" "light" "origin" "888 1328 424" } { "classname" "light" "origin" "160 1352 960" "light" "150" } { "light" "150" "origin" "368 1104 1000" "classname" "light" } { "classname" "light" "origin" "1048 1504 1000" "light" "150" } { "classname" "light" "origin" "992 992 1048" "light" "150" } { "classname" "light" "origin" "48 1384 1008" "light" "100" } { "light" "150" "origin" "1080 1144 1048" "classname" "light" } { "classname" "light" "origin" "968 824 976" "light" "150" } { "classname" "light" "origin" "896 1328 1000" "light" "150" } { "classname" "light" "origin" "368 1616 1000" "light" "175" } { "classname" "light" "origin" "256 1496 824" "light" "150" } { "light" "150" "origin" "256 1352 824" "classname" "light" } { "classname" "light" "origin" "856 1368 536" "light" "200" } { "light" "150" "origin" "552 1360 536" "classname" "light" } { "classname" "light" "origin" "872 1552 1056" "light" "150" } { "classname" "light" "origin" "1032 1056 904" "light" "150" } { "light" "150" "origin" "1080 1184 904" "classname" "light" } { "classname" "light" "origin" "864 848 904" "light" "150" } { "classname" "light" "origin" "312 1496 1016" "light" "175" } { "light" "200" "origin" "704 1368 808" "classname" "light" } { "light" "150" "origin" "464 816 904" "classname" "light" } { "light" "200" "origin" "944 888 800" "classname" "light" } { "light" "150" "origin" "888 1112 728" "classname" "light" } { "light" "175" "origin" "1008 1504 728" "classname" "light" } { "light" "200" "origin" "720 1848 1200" "classname" "light" } { "light" "200" "origin" "704 888 672" "classname" "light" } { "light" "175" "origin" "512 1456 1040" "classname" "light" } { "light" "150" "origin" "440 840 380" "classname" "light" } { "light" "150" "origin" "720 1848 1028" "classname" "light" } { "light" "150" "origin" "720 1936 1024" "classname" "light" } { "origin" "544 2128 984" "classname" "light" "light" "200" } { "light" "200" "origin" "712 1912 576" "classname" "light" } { "light" "300" "origin" "720 2544 856" "classname" "light" } { "light" "200" "origin" "888 2048 592" "classname" "light" } { "origin" "704 2496 1128" "classname" "light" } { "origin" "512 2048 976" "classname" "light" "light" "150" } { "origin" "952 2328 528" "classname" "light" "light" "200" } { "classname" "light" "origin" "700 2760 808" "light" "200" } { "classname" "light" "origin" "700 2800 616" "light" "200" } { "classname" "light" "origin" "584 2780 584" "light" "175" } { "light" "175" "origin" "808 2780 584" "classname" "light" } { "sounds" "3" "wait" "-1" "targetname" "t29" "classname" "func_door" "angle" "270" "model" "*15" } { "message" "This door is opened elsewhere..." "wait" "-1" "classname" "func_door" "angle" "90" "model" "*16" } { "classname" "light" "origin" "424 2304 1000" "light" "200" } { "light" "300" "origin" "696 2880 1062" "classname" "light_flame_small_yellow" } { "light" "200" "classname" "light" "origin" "864 2128 984" } { "classname" "light_flame_large_yellow" "origin" "702 2154 1228" "light" "0" } { "classname" "light" "origin" "832 2008 1136" "light" "200" } { "classname" "light" "origin" "584 2008 1136" "light" "200" } { "light" "200" "origin" "272 2016 1136" "classname" "light" } { "classname" "light" "origin" "272 2320 1136" "light" "150" } { "light" "150" "origin" "1104 2408 984" "classname" "light" } { "sounds" "2" "classname" "func_plat" "wait" "4" "model" "*17" } { "classname" "light" "origin" "700 2844 996" "light" "200" } { "classname" "light" "origin" "704 2216 1252" } { "origin" "936 2304 1252" "classname" "light" } { "classname" "light" "origin" "936 2536 1252" } { "light" "300" "classname" "light" "origin" "488 2536 1252" } { "origin" "488 2304 1252" "classname" "light" "light" "300" } { "light" "0" "origin" "998 2306 1228" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "998 2534 1228" "light" "0" } { "light" "0" "origin" "426 2534 1228" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "426 2306 1228" "light" "0" } { "classname" "light" "origin" "704 2152 984" "light" "200" } { "classname" "light_flame_small_yellow" "origin" "1160 2400 1038" "light" "250" } { "origin" "840 2536 630" "classname" "light_flame_small_yellow" "light" "250" } { "classname" "light_flame_small_yellow" "origin" "584 2544 630" "light" "250" } { "light" "250" "origin" "408 2304 694" "classname" "light_flame_small_yellow" } { "light" "200" "classname" "light" "origin" "960 2632 528" } { "classname" "light" "origin" "960 2480 528" "light" "150" } { "classname" "light" "origin" "456 2304 624" "light" "175" } { "classname" "light" "origin" "704 2416 576" "light" "250" } { "light" "150" "origin" "728 2184 528" "classname" "light" } { "classname" "light" "origin" "512 2176 528" "light" "150" } { "classname" "light" "origin" "832 2336 656" "light" "175" } { "light" "175" "origin" "592 2336 656" "classname" "light" } { "classname" "light" "origin" "808 2584 576" "light" "150" } { "light" "150" "origin" "616 2576 576" "classname" "light" } { "classname" "light_flame_small_yellow" "origin" "488 2712 694" "light" "250" } { "classname" "light" "origin" "488 2624 608" "light" "175" } { "classname" "light" "origin" "480 2464 608" "light" "175" } { "light" "250" "origin" "184 2184 1038" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "512 2096 1038" "light" "250" } { "classname" "light" "origin" "224 2184 976" "light" "150" } { "classname" "light" "origin" "848 2024 992" "light" "200" } { "classname" "light" "origin" "256 1992 1000" "light" "150" } { "classname" "light" "origin" "272 2376 1000" "light" "200" } { "classname" "light" "origin" "1112 2208 1032" "light" "150" } { "light" "0" "origin" "698 2860 1228" "classname" "light_flame_large_yellow" } { "origin" "700 2808 1252" "classname" "light" } { "light" "250" "origin" "472 2632 1062" "classname" "light" } { "classname" "light" "origin" "952 2632 1062" "light" "250" } { "light" "150" "origin" "952 2424 894" "classname" "light" } { "classname" "light" "origin" "480 2424 894" "light" "150" } { "light" "150" "origin" "896 2296 966" "classname" "light" } { "classname" "light" "origin" "704 2304 966" "light" "150" } { "light" "150" "origin" "552 2304 966" "classname" "light" } { "light" "250" "origin" "704 2184 406" "classname" "light" } { "light" "150" "origin" "712 2000 406" "classname" "light" } { "light" "200" "origin" "504 2224 400" "classname" "light" } { "light" "200" "origin" "960 2576 400" "classname" "light" } { "light" "150" "origin" "960 2400 400" "classname" "light" } { "light" "150" "origin" "808 1112 592" "classname" "light" } { "classname" "light" "origin" "600 1112 592" "light" "150" } { "light" "175" "origin" "1016 128 936" "classname" "light" } { "classname" "light" "origin" "392 128 936" "light" "175" } { "light" "150" "origin" "848 -64 1304" "classname" "light" } { "classname" "light" "origin" "560 -64 1304" "light" "150" } { "light" "175" "origin" "1248 832 1496" "classname" "light" } { "light" "150" "origin" "1096 872 1496" "classname" "light" } { "light" "150" "origin" "896 2208 976" "classname" "light" } { "classname" "light" "origin" "1096 200 1512" "light" "350" } { "light" "350" "origin" "264 192 1512" "classname" "light" } { "light" "175" "origin" "488 448 1264" "classname" "light" } { "origin" "1048 728 1456" "classname" "light" "light" "200" } { "light" "125" "origin" "1328 928 1448" "classname" "light" } { "light" "225" "origin" "696 672 1320" "classname" "light" } { "origin" "816 -56 1640" "classname" "light" } { "classname" "light" "origin" "584 -56 1640" } { "light" "175" "origin" "880 96 1376" "classname" "light" } { "classname" "light" "origin" "528 96 1376" "light" "175" } { "light" "200" "origin" "960 344 1072" "classname" "light" } { "classname" "light" "origin" "1120 264 1072" "light" "200" } { "light" "175" "origin" "1208 96 1016" "classname" "light" } { "light" "175" "origin" "1024 360 968" "classname" "light" } { "classname" "light" "origin" "328 336 968" "light" "150" } { "classname" "light" "origin" "416 424 1072" "light" "200" } { "light" "200" "origin" "296 256 1072" "classname" "light" } { "light" "150" "origin" "704 48 1040" "classname" "light" } { "light" "175" "origin" "384 464 976" "classname" "light" } { "classname" "light" "origin" "224 264 976" "light" "150" } { "light" "150" "origin" "952 2192 416" "classname" "light" } { "classname" "light" "origin" "1040 -464 1016" "light" "150" } { "sounds" "2" "spawnflags" "1" "classname" "func_plat" "model" "*18" } { "light" "250" "origin" "1072 -272 1262" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "1024 -272 1200" "light" "150" } { "light" "200" "origin" "624 -240 1328" "classname" "light" } { "light" "175" "origin" "1080 -624 1168" "classname" "light" } { "origin" "456 -576 1230" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "504 -576 1168" "light" "175" } { "origin" "624 -448 924" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "624 -704 924" } { "light" "125" "origin" "664 -448 880" "classname" "light" } { "classname" "light" "origin" "624 -488 880" "light" "125" } { "light" "125" "origin" "584 -448 880" "classname" "light" } { "classname" "light" "origin" "624 -408 880" "light" "125" } { "light" "125" "origin" "624 -664 880" "classname" "light" } { "classname" "light" "origin" "664 -704 880" "light" "125" } { "light" "125" "origin" "624 -744 880" "classname" "light" } { "classname" "light" "origin" "584 -704 880" "light" "125" } { "light" "250" "origin" "296 -96 968" "classname" "light" } { "light" "250" "origin" "1112 -96 968" "classname" "light" } { "light" "175" "origin" "1056 -224 968" "classname" "light" } { "light" "500" "origin" "-264 2120 1504" "classname" "light" } { "spawnflags" "2064" "angle" "0" "classname" "func_door" "wait" "-1" "model" "*19" } { "sounds" "3" "classname" "func_door" "angle" "180" "spawnflags" "2064" "wait" "-1" "model" "*20" } { "light" "200" "origin" "704 32 952" "classname" "light" } { "target" "t101" "spawnflags" "256" "targetname" "t23" "angle" "90" "origin" "-248 1560 1224" "classname" "monster_wizard" } { "target" "t23" "classname" "trigger_once" "model" "*21" } { "origin" "-280 1560 1348" "classname" "item_armor2" } { "origin" "-488 2112 1220" "classname" "item_health" } { "classname" "item_health" "origin" "-488 2064 1220" } { "spawnflags" "1536" "origin" "-272 1784 1156" "classname" "item_shells" } { "spawnflags" "256" "target" "t25" "targetname" "t24" "origin" "888 1640 1028" "classname" "path_corner" } { "spawnflags" "256" "target" "t24" "targetname" "t25" "classname" "path_corner" "origin" "624 1264 1028" } { "spawnflags" "256" "target" "t24" "origin" "928 1672 1028" "classname" "monster_wizard" } { "spawnflags" "2304" "target" "t26" "classname" "trigger_once" "model" "*22" } { "target" "t27" "targetname" "t28" "origin" "568 2040 928" "classname" "path_corner" } { "target" "t28" "targetname" "t27" "classname" "path_corner" "origin" "368 2044 928" } { "target" "t27" "origin" "472 2040 944" "classname" "monster_ogre" "spawnflags" "1" } { "sounds" "2" "target" "t29" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*23" } { "sounds" "3" "angle" "180" "classname" "func_door" "model" "*24" } { "angle" "0" "classname" "func_door" "model" "*25" } { "light" "175" "origin" "1112 2520 964" "classname" "light" } { "origin" "104 1308 892" "classname" "item_health" } { "spawnflags" "2048" "origin" "704 1344 936" "classname" "item_key1" "sounds" "1" } { "target" "t34" "angle" "180" "origin" "920 2040 544" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t35" "targetname" "t34" "origin" "864 2044 528" "classname" "path_corner" } { "target" "t37" "targetname" "t35" "classname" "path_corner" "origin" "704 2048 528" } { "target" "t34" "targetname" "t36" "origin" "704 2048 528" "classname" "path_corner" } { "target" "t36" "targetname" "t37" "classname" "path_corner" "origin" "704 1808 528" } { "targetname" "t38" "angle" "270" "origin" "456 2476 544" "classname" "monster_ogre" } { "target" "t38" "classname" "trigger_once" "model" "*26" } { "targetname" "t29" "angle" "0" "origin" "336 2272 952" "classname" "monster_knight" "spawnflags" "768" } { "targetname" "t39" "spawnflags" "1" "wait" "-1" "angle" "-2" "classname" "func_door" "sounds" "1" "model" "*27" } { "targetname" "t39" "angle" "270" "origin" "712 2540 448" "classname" "monster_ogre" } { "target" "t39" "classname" "trigger_once" "model" "*28" } { "classname" "light" "origin" "712 2544 440" "light" "200" } { "classname" "item_health" "origin" "1064 2184 920" "spawnflags" "1024" } { "spawnflags" "1" "origin" "1128 2184 920" "classname" "item_health" } { "classname" "item_spikes" "origin" "816 2840 920" } { "origin" "816 2800 920" "classname" "item_spikes" } { "spawnflags" "256" "classname" "monster_wizard" "origin" "1656 1496 968" "angle" "180" "target" "t41" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t40" "targetname" "t39" "model" "*29" } { "classname" "info_teleport_destination" "origin" "984 1496 1000" "angle" "180" "targetname" "t40" } { "spawnflags" "256" "classname" "path_corner" "origin" "912 1496 1000" "targetname" "t41" "target" "t42" } { "spawnflags" "256" "origin" "528 1368 1000" "classname" "path_corner" "targetname" "t42" "target" "t41" } { "classname" "item_health" "origin" "408 2640 520" } { "classname" "item_shells" "origin" "456 2672 520" "spawnflags" "1" } { "angle" "0" "origin" "80 864 968" "classname" "monster_wizard" "target" "t44" } { "targetname" "t119" "spawnflags" "2" "classname" "trigger_teleport" "target" "t45" "model" "*30" } { "classname" "info_teleport_destination" "origin" "432 856 952" "angle" "45" "targetname" "t45" } { "classname" "path_corner" "origin" "496 872 952" "target" "t43" "targetname" "t44" } { "origin" "872 1056 952" "classname" "path_corner" "targetname" "t43" "target" "t44" } { "classname" "trigger_once" "spawnflags" "1792" "target" "t39" "model" "*31" } { "spawnflags" "1024" "classname" "monster_knight" "origin" "1168 56 904" "angle" "135" "target" "t49" "targetname" "t67" } { "classname" "monster_ogre" "origin" "1800 224 920" "angle" "180" "target" "t116" "spawnflags" "256" } { "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t49" "lip" "-24" "model" "*32" } { "wait" "-1" "angle" "-1" "classname" "func_door" "spawnflags" "1" "targetname" "t39" "lip" "-24" "model" "*33" } { "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t29" "lip" "-24" "model" "*34" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t46" "model" "*35" } { "classname" "info_teleport_destination" "origin" "1104 232 880" "angle" "180" "targetname" "t46" } { "classname" "path_corner" "origin" "1064 256 880" "target" "t47" "targetname" "t48" "spawnflags" "256" } { "origin" "312 232 880" "classname" "path_corner" "targetname" "t47" "target" "t48" "spawnflags" "256" } { "classname" "info_teleport_destination" "origin" "704 -40 1256" "angle" "90" "targetname" "t50" } { "classname" "trigger_once" "target" "t52" "model" "*36" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t50" "targetname" "t52" "model" "*37" } { "angle" "90" "origin" "570 -898 1300" "classname" "monster_wizard" "targetname" "t52" } { "classname" "item_shells" "origin" "216 120 880" "spawnflags" "1" } { "classname" "item_health" "origin" "192 232 880" } { "origin" "192 192 880" "classname" "item_health" "spawnflags" "1024" } { "classname" "item_shells" "origin" "-216 1464 888" } { "classname" "item_health" "origin" "816 1160 512" "spawnflags" "1024" } { "spawnflags" "1" "origin" "816 1120 512" "classname" "item_health" } { "classname" "monster_wizard" "origin" "944 840 956" "angle" "135" "target" "t53" "targetname" "t64" } { "classname" "trigger_once" "target" "t64" "model" "*38" } { "classname" "monster_knight" "origin" "704 392 1280" "angle" "270" "target" "t65" "spawnflags" "1" } { "classname" "path_corner" "origin" "704 208 1264" "targetname" "t65" "target" "t66" } { "origin" "704 496 1264" "classname" "path_corner" "targetname" "t66" "target" "t65" } { "classname" "trigger_once" "target" "t67" "model" "*39" } { "sounds" "1" "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t72" "model" "*40" } { "sounds" "1" "classname" "func_door" "wait" "-1" "angle" "-2" "targetname" "t72" "model" "*41" } { "classname" "trigger_once" "target" "t72" "model" "*42" } { "classname" "info_null" "origin" "852 -580 820" "targetname" "t73" } { "classname" "light" "origin" "856 -584 936" "light" "400" "target" "t73" } { "classname" "light" "origin" "920 -448 744" "light" "150" } { "light" "150" "origin" "760 -448 744" "classname" "light" } { "classname" "light" "origin" "552 -424 744" "light" "150" } { "light" "150" "origin" "560 -728 744" "classname" "light" } { "classname" "light" "origin" "776 -712 744" "light" "150" } { "light" "150" "origin" "936 -712 744" "classname" "light" } { "classname" "path_corner" "origin" "652 -576 952" "targetname" "t75" "target" "t74" } { "origin" "908 -576 952" "classname" "path_corner" "targetname" "t74" "target" "t75" } { "classname" "monster_ogre" "origin" "816 -260 952" "angle" "270" "targetname" "t72" } { "classname" "monster_ogre" "origin" "724 -260 952" "angle" "270" "targetname" "t72" "spawnflags" "256" } { "classname" "item_health" "origin" "632 -548 820" "spawnflags" "3072" } { "origin" "672 -548 820" "classname" "item_health" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t76" "model" "*43" } { "sounds" "1" "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t76" "model" "*44" } { "light" "150" "origin" "1040 -712 1016" "classname" "light" } { "origin" "1112 -576 942" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "1064 -576 896" "light" "150" } { "classname" "light" "origin" "888 -80 968" "light" "175" } { "light" "175" "origin" "512 -80 968" "classname" "light" } { "classname" "item_armor2" "origin" "1184 -96 920" } { "classname" "monster_ogre" "origin" "392 8 912" "angle" "315" "targetname" "t77" "spawnflags" "256" } { "classname" "trigger_once" "target" "t77" "model" "*45" } { "classname" "item_health" "origin" "336 -224 888" "spawnflags" "1" } { "classname" "item_spikes" "origin" "968 16 888" "spawnflags" "1" } { "classname" "item_health" "origin" "560 2808 516" "spawnflags" "1" } { "classname" "path_corner" "origin" "1056 -384 824" "targetname" "t78" "target" "t79" "spawnflags" "256" } { "origin" "1056 -736 824" "classname" "path_corner" "targetname" "t79" "target" "t78" "spawnflags" "256" } { "classname" "monster_ogre" "origin" "1064 -656 840" "angle" "90" "target" "t78" "spawnflags" "257" } { "angle" "90" "origin" "848 -880 952" "classname" "monster_ogre" "targetname" "t72" } { "classname" "item_shells" "origin" "1160 16 1248" } { "classname" "item_health" "origin" "280 64 1248" } { "classname" "item_rockets" "origin" "648 -256 928" "spawnflags" "1025" } { "classname" "item_spikes" "origin" "648 -304 1248" } { "origin" "696 -304 1248" "classname" "item_spikes" } { "classname" "light_flame_small_yellow" "origin" "768 -352 1230" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*46" } { "target" "t83" "classname" "trigger_multiple" "wait" ".8" "model" "*47" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*48" } { "target" "t83" "classname" "trigger_multiple" "wait" ".8" "model" "*49" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*50" } { "targetname" "t83" "classname" "trap_spikeshooter" "origin" "1108 -576 1140" "spawnflags" "1" "angle" "180" } { "targetname" "t83" "angle" "90" "spawnflags" "1" "origin" "768 -796 1140" "classname" "trap_spikeshooter" } { "origin" "1112 -576 1230" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "768 -800 1230" } { "classname" "light" "origin" "712 -756 1168" "light" "175" } { "light" "175" "origin" "768 -424 1168" "classname" "light" } { "light" "175" "origin" "888 -744 956" "classname" "light" } { "classname" "light" "origin" "888 -408 956" "light" "175" } { "origin" "384 -224 888" "classname" "item_shells" } { "origin" "584 1784 920" "classname" "item_health" } { "origin" "832 2064 920" "classname" "item_shells" } { "target" "t72" "classname" "trigger_once" "model" "*51" } { "target" "t85" "targetname" "t84" "origin" "1560 216 896" "classname" "path_corner" } { "target" "t48" "targetname" "t85" "classname" "path_corner" "origin" "1456 216 896" } { "origin" "704 1368 516" "classname" "weapon_supernailgun" } { "spawnflags" "1" "origin" "184 1928 920" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "656 1816 528" "spawnflags" "768" } { "classname" "item_shells" "origin" "1072 -800 820" "spawnflags" "1024" } { "classname" "monster_ogre" "origin" "840 -40 1276" "angle" "180" "targetname" "t86" "spawnflags" "768" } { "classname" "trigger_once" "target" "t86" "model" "*52" } { "classname" "light" "origin" "472 -576 876" "light" "150" } { "classname" "item_shells" "origin" "656 680 1256" "spawnflags" "1536" } { "angle" "270" "origin" "880 2224 536" "classname" "monster_knight" "spawnflags" "256" } { "angle" "180" "origin" "1112 2424 944" "classname" "monster_ogre" "spawnflags" "1281" } { "targetname" "t88" "target" "t87" "origin" "360 384 880" "classname" "path_corner" "spawnflags" "1280" } { "target" "t88" "targetname" "t87" "classname" "path_corner" "origin" "504 160 880" "spawnflags" "1280" } { "target" "t87" "angle" "315" "origin" "384 320 896" "classname" "monster_knight" "spawnflags" "1280" } { "spawnflags" "257" "targetname" "t86" "angle" "0" "origin" "376 120 1272" "classname" "monster_ogre" } { "origin" "776 1368 916" "classname" "item_shells" "spawnflags" "1024" } { "classname" "item_spikes" "origin" "184 1968 920" "spawnflags" "1" } { "classname" "monster_wizard" "origin" "312 936 944" "angle" "45" "spawnflags" "769" } { "classname" "monster_knight" "origin" "704 -80 908" "angle" "90" } { "angle" "0" "origin" "568 -56 1276" "classname" "monster_ogre" "targetname" "t86" "spawnflags" "768" } { "spawnflags" "1536" "targetname" "t90" "target" "t89" "origin" "720 1696 924" "classname" "path_corner" } { "spawnflags" "1536" "target" "t90" "targetname" "t89" "classname" "path_corner" "origin" "720 1416 924" } { "spawnflags" "1537" "target" "t90" "origin" "704 1784 948" "classname" "monster_ogre" } { "classname" "func_door_secret" "angle" "0" "spawnflags" "1" "targetname" "t91" "model" "*53" "t_length" "73" // svdijk -- added to prevent z-fighting } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*54" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*55" } { "classname" "func_button" "wait" "-1" "angle" "-2" "target" "t92" "model" "*56" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*57" } { "classname" "func_button" "wait" "-1" "angle" "-2" "target" "t92" "model" "*58" } { "classname" "trigger_counter" "count" "5" "target" "t91" "targetname" "t92" "model" "*59" } { "classname" "light" "origin" "680 -920 1144" "light" "150" } { "classname" "item_spikes" "origin" "752 -876 928" "spawnflags" "1" } { "spawnflags" "3" "angle" "0" "classname" "func_door_secret" "targetname" "t91" "model" "*60" "t_length" "73" // svdijk -- added to prevent z-fighting } { "light" "150" "origin" "680 -256 1144" "classname" "light" } { "classname" "trigger_once" "spawnflags" "1792" "target" "t72" "model" "*61" } { "classname" "trigger_secret" "sounds" "1" "targetname" "t8" "model" "*62" } { "angle" "270" "origin" "704 624 1280" "classname" "monster_knight" "spawnflags" "1" } { "angle" "225" "origin" "1016 -440 1128" "classname" "monster_knight" } { "angle" "180" "origin" "1024 -728 1128" "classname" "monster_knight" } { "spawnflags" "256" "angle" "180" "origin" "1008 -568 1128" "classname" "monster_knight" } { "spawnflags" "256" "classname" "monster_knight" "origin" "304 2312 952" "angle" "0" "targetname" "t29" } { "spawnflags" "1025" "classname" "monster_knight" "origin" "272 136 896" "angle" "45" } { "classname" "monster_wizard" "origin" "784 -576 960" "angle" "0" "target" "t74" "spawnflags" "1" } { "classname" "item_health" "origin" "732 -936 928" } { "origin" "772 -936 928" "classname" "item_health" } { "spawnflags" "256" "classname" "monster_knight" "origin" "704 -248 1272" "angle" "0" } { "classname" "path_corner" "origin" "1328 928 1396" "targetname" "t93" "target" "t94" "spawnflags" "512" } { "origin" "1176 928 1396" "classname" "path_corner" "target" "t93" "targetname" "t94" "spawnflags" "512" } { "classname" "monster_knight" "origin" "1192 884 1412" "angle" "0" "target" "t93" "spawnflags" "513" } { "classname" "monster_knight" "origin" "704 2376 944" "angle" "90" } { "classname" "monster_knight" "origin" "888 2312 944" "angle" "180" "targetname" "t95" } { "angle" "0" "origin" "512 2304 944" "classname" "monster_knight" "targetname" "t95" "spawnflags" "768" } { "classname" "trigger_once" "target" "t95" "model" "*63" } { "spawnflags" "256" "angle" "315" "origin" "728 2312 536" "classname" "monster_knight" } { "light" "200" "origin" "1296 1528 936" "classname" "light" } { "light" "250" "origin" "1432 1360 982" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "1400 1360 920" "classname" "light" } { "light" "200" "origin" "1248 1344 680" "classname" "light" } { "lip" "-384" "wait" "-1" "angle" "90" "classname" "func_door" "targetname" "t98" "model" "*64" } { "light" "150" "origin" "1152 1328 584" "classname" "light" } { "origin" "1376 1480 864" "classname" "item_health" } { "sounds" "1" "classname" "trigger_secret" "model" "*65" } { "classname" "func_button" "sounds" "1" "angle" "0" "wait" "-1" "target" "t97" "model" "*66" } { "classname" "func_button" "wait" "-1" "angle" "0" "sounds" "1" "target" "t97" "model" "*67" } { "classname" "trigger_counter" "targetname" "t97" "target" "t98" "model" "*68" } { "classname" "light" "origin" "880 -888 968" "light" "150" } { "light" "150" "origin" "880 -264 968" "classname" "light" } { "angle" "180" "origin" "1112 2344 944" "classname" "monster_ogre" "spawnflags" "769" } { "angle" "270" "origin" "1120 880 1412" "classname" "monster_ogre" "spawnflags" "257" } { "map" "e1m8" "classname" "trigger_changelevel" "model" "*69" } { "light" "175" "origin" "824 -756 1168" "classname" "light" } { "classname" "light" "origin" "1080 -528 1168" "light" "175" } { "classname" "monster_wizard" "origin" "672 -392 1024" "angle" "315" "spawnflags" "257" } { "classname" "monster_knight" "origin" "1008 -656 1128" "angle" "180" "spawnflags" "768" } { "origin" "520 1064 440" "classname" "air_bubbles" } { "classname" "item_spikes" "origin" "16 1432 892" } { "classname" "trigger_once" "message" "A secret cave has opened..." "targetname" "t98" "model" "*70" } { "target" "t4" "health" "1" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*71" } { "target" "t2" "health" "1" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*72" } { "target" "t49" "spawnflags" "769" "angle" "135" "origin" "1208 128 904" "classname" "monster_demon1" } { "spawnflags" "769" "angle" "45" "origin" "288 160 896" "classname" "monster_demon1" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "692 -884 952" "angle" "90" } { "classname" "monster_ogre" "origin" "-312 1648 1372" "angle" "90" "targetname" "t23" "spawnflags" "768" } { "angle" "90" "origin" "-192 1648 1372" "classname" "monster_ogre" "targetname" "t23" "spawnflags" "768" } { "classname" "monster_ogre" "origin" "704 1288 540" "angle" "270" "spawnflags" "768" } { "targetname" "t101" "target" "t106" "spawnflags" "770" "classname" "trigger_teleport" "model" "*73" } { "spawnflags" "768" "targetname" "t101" "angle" "270" "origin" "-256 2424 1288" "classname" "monster_wizard" } { "targetname" "t101" "origin" "-248 2440 1280" "classname" "trigger_relay" } { "targetname" "t29" "spawnflags" "256" "angle" "0" "origin" "144 2648 1024" "classname" "monster_wizard" } { "targetname" "t29" "spawnflags" "768" "classname" "monster_wizard" "origin" "144 2592 1024" "angle" "0" } { "targetname" "t29" "spawnflags" "768" "angle" "0" "origin" "144 2536 1024" "classname" "monster_wizard" } { "targetname" "t29" "target" "t102" "spawnflags" "258" "classname" "trigger_teleport" "model" "*74" } { "targetname" "t29" "target" "t103" "spawnflags" "770" "classname" "trigger_teleport" "model" "*75" } { "targetname" "t29" "target" "t104" "spawnflags" "770" "classname" "trigger_teleport" "model" "*76" } { "angle" "270" "targetname" "t102" "spawnflags" "256" "origin" "704 2656 1008" "classname" "info_teleport_destination" } { "angle" "270" "targetname" "t103" "spawnflags" "768" "classname" "info_teleport_destination" "origin" "920 2520 1008" } { "angle" "0" "targetname" "t104" "spawnflags" "768" "origin" "592 2192 1008" "classname" "info_teleport_destination" } { "sounds" "1" "classname" "func_door" "angle" "0" "wait" "-1" "speed" "150" "targetname" "t105" "model" "*77" } { "classname" "monster_demon1" "origin" "1056 -880 1128" "angle" "90" "spawnflags" "768" "targetname" "t105" } { "classname" "trigger_once" "spawnflags" "768" "target" "t105" "model" "*78" } { "classname" "light" "origin" "1056 -920 1184" "light" "125" } { "classname" "trigger_relay" "origin" "1104 -864 1120" "target" "t105" } { "classname" "monster_ogre" "origin" "1120 768 1416" "angle" "180" "spawnflags" "769" } { "classname" "air_bubbles" "origin" "884 1616 440" } { "targetname" "t106" "spawnflags" "768" "angle" "270" "origin" "-264 2232 1296" "classname" "info_teleport_destination" } { "classname" "path_corner" "origin" "568 1984 928" "targetname" "t107" "target" "t108" "spawnflags" "256" } { "origin" "424 1960 928" "classname" "path_corner" "target" "t107" "spawnflags" "256" "targetname" "t111" } { "classname" "path_corner" "origin" "704 2024 928" "targetname" "t108" "target" "t109" "spawnflags" "256" } { "origin" "712 1712 928" "classname" "path_corner" "targetname" "t109" "target" "t110" "spawnflags" "256" } { "classname" "path_corner" "origin" "712 1416 928" "targetname" "t110" "target" "t109" "spawnflags" "256" } { "classname" "func_door" "angle" "-2" "wait" "-1" "lip" "-24" "targetname" "t26" "spawnflags" "2304" "model" "*79" } { "classname" "monster_ogre" "origin" "240 2048 944" "angle" "0" "spawnflags" "257" "target" "t111" } { "target" "t23" "spawnflags" "1792" "classname" "trigger_once" "model" "*80" } { "classname" "monster_knight" "origin" "576 2768 536" "angle" "0" "spawnflags" "256" } { "spawnflags" "256" "angle" "180" "origin" "824 2776 536" "classname" "monster_knight" } { "classname" "monster_wizard" "origin" "704 -1032 1024" "angle" "90" "spawnflags" "256" "targetname" "t52" } { "angle" "90" "origin" "760 -1032 1024" "classname" "monster_wizard" "spawnflags" "768" "targetname" "t114" } { "classname" "monster_wizard" "origin" "816 -1032 1024" "angle" "90" "spawnflags" "768" "targetname" "t114" } { "targetname" "t52" "classname" "trigger_teleport" "spawnflags" "258" "target" "t112" "model" "*81" } { "classname" "trigger_teleport" "spawnflags" "770" "target" "t113" "targetname" "t114" "model" "*82" } { "targetname" "t114" "classname" "trigger_teleport" "spawnflags" "770" "target" "t115" "model" "*83" } { "classname" "info_teleport_destination" "origin" "896 224 1352" "angle" "135" "spawnflags" "256" "targetname" "t112" } { "classname" "info_teleport_destination" "origin" "488 1648 1016" "angle" "315" "spawnflags" "768" "targetname" "t113" } { "classname" "trigger_once" "spawnflags" "768" "target" "t114" "model" "*84" } { "classname" "info_teleport_destination" "origin" "800 904 928" "angle" "90" "spawnflags" "768" "targetname" "t115" } { "angle" "270" "origin" "-256 2232 1242" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "-256 2096 1218" "classname" "weapon_supershotgun" } { "angle" "270" "origin" "704 424 1266" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 2488 946" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 1968 546" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "704 104 898" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 1568 938" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "704 1344 912" "classname" "weapon_rocketlauncher" } { "angle" "0" "origin" "712 -576 840" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "944 -576 816" "classname" "weapon_nailgun" } { "angle" "180" "origin" "1064 -576 1128" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "696 584 1256" "classname" "weapon_grenadelauncher" } { "classname" "light" "origin" "316 804 780" "light" "150" } { "classname" "light" "origin" "316 804 644" "light" "75" } { "classname" "item_rockets" "origin" "298 710 706" "spawnflags" "1" } { "classname" "item_shells" "origin" "988 -928 1104" "spawnflags" "1" } { "classname" "item_health" "origin" "-56 2112 1220" "spawnflags" "3584" } { "classname" "item_health" "origin" "-56 2072 1220" "spawnflags" "2305" } { "spawnflags" "1" "origin" "584 2416 512" "classname" "item_spikes" } { "origin" "688 1392 516" "classname" "item_spikes" } { "classname" "item_artifact_invulnerability" "origin" "712 2312 948" "spawnflags" "1792" } { "origin" "32 1392 916" "classname" "item_artifact_envirosuit" } { "mangle" "26 310 0" "origin" "384 488 1552" "classname" "info_intermission" } { "light" "100" "origin" "800 1160 464" "classname" "light" } { "classname" "light" "origin" "608 1160 464" "light" "100" } { "light" "100" "origin" "604 1472 464" "classname" "light" } { "target" "t40" "classname" "trigger_teleport" "model" "*85" } { "mangle" "-20 75 0" "origin" "456 2144 568" "classname" "info_intermission" } { "mangle" "10 80 0" "origin" "464 1032 1000" "classname" "info_intermission" } { "mangle" "20 135 0" "origin" "1080 -752 1008" "classname" "info_intermission" } { "classname" "trigger_secret" "model" "*86" } { "classname" "path_corner" "origin" "1632 216 896" "targetname" "t116" "target" "t84" } { "classname" "item_spikes" "origin" "1200 48 872" "spawnflags" "1" } { "classname" "item_spikes" "origin" "928 2664 320" "spawnflags" "1" } { "classname" "item_shells" "origin" "1240 768 1384" "spawnflags" "1" } { "classname" "item_shells" "origin" "-88 2160 1224" "spawnflags" "2049" } { "classname" "info_player_coop" "origin" "-208 2272 1240" "angle" "270" } { "angle" "270" "origin" "-304 2272 1240" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-352 2272 1240" "angle" "270" } { "light" "200" "origin" "1288 1648 956" "classname" "light" } { "classname" "item_spikes" "origin" "-264 1464 888" } { "spawnflags" "1792" "origin" "1296 1488 888" "classname" "item_artifact_invisibility" } { "spawnflags" "1792" "classname" "func_wall" "model" "*87" } { "classname" "func_wall" "spawnflags" "1792" "model" "*88" } { "target" "t118" "targetname" "t117" "origin" "-176 1640 888" "classname" "path_corner" } { "targetname" "t118" "target" "t117" "classname" "path_corner" "origin" "-320 1640 888" } { "target" "t117" "origin" "-256 1632 904" "classname" "monster_knight" "spawnflags" "1" } { "origin" "1376 1424 864" "classname" "weapon_grenadelauncher" } { "spawnflags" "1" "targetname" "t120" "target" "t119" "classname" "trigger_counter" "model" "*89" } { "target" "t120" "targetname" "t53" "classname" "trigger_once" "model" "*90" } { "target" "t120" "targetname" "t39" "classname" "trigger_once" "model" "*91" } { "classname" "light" "origin" "480 2568 568" "light" "125" } { "origin" "162 1482 976" "classname" "ambient_drip" } { "origin" "786 1010 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "778 1210 584" } { "origin" "594 1202 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "602 1010 584" } { "origin" "786 1514 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "794 1698 584" } { "origin" "618 1690 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "618 1522 584" } { "origin" "698 1362 584" "classname" "ambient_drip" } { "origin" "714 1970 592" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "898 2170 592" } { "origin" "938 2346 592" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "682 2298 592" } { "origin" "458 2306 592" "classname" "ambient_drip" } { "origin" "458 1690 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "322 1506 880" } { "origin" "338 1226 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "466 1090 880" } { "origin" "394 882 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "674 810 880" } { "origin" "914 818 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "922 1034 880" } { "origin" "1082 1266 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "994 1442 880" } { "origin" "898 1714 880" "classname" "ambient_drip" } { "origin" "706 1362 1080" "classname" "ambient_drip" } { "origin" "1194 1522 1032" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1314 1354 1032" } { "origin" "442 354 920" "classname" "ambient_swamp1" } { "origin" "978 314 920" "classname" "ambient_swamp2" } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/maps/e1m4.ent.orig����������������������������������������������������0000644�0000000�0000000�00000125145�12425501423�020005� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "message" "the Grisly Grotto" "worldtype" "0" "classname" "worldspawn" "wad" "gfx/wizard.wad" "sounds" "5" } { "classname" "light" "origin" "464 480 1656" "light" "300" } { "light" "400" "origin" "712 296 1512" "classname" "light" } { "sounds" "3" "angle" "180" "classname" "func_door" "model" "*1" } { "angle" "0" "classname" "func_door" "model" "*2" } { "classname" "light_flame_small_yellow" "origin" "560 -112 1374" } { "origin" "848 -112 1374" "classname" "light_flame_small_yellow" } { "origin" "760 656 1536" "classname" "light" } { "light" "400" "origin" "834 498 1040" "classname" "light" } { "light" "200" "classname" "light" "origin" "944 728 1456" } { "classname" "light_flame_small_yellow" "origin" "1016 80 998" } { "origin" "392 80 998" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "680 1224 516" "light" "200" } { "light" "200" "origin" "704 992 516" "classname" "light" } { "light" "200" "origin" "696 1608 628" "classname" "light" } { "origin" "704 1368 588" "classname" "light" } { "origin" "816 1616 444" "classname" "light" } { "classname" "light" "origin" "712 1728 444" } { "origin" "592 1608 444" "classname" "light" } { "classname" "light" "origin" "624 1096 444" } { "light" "300" "origin" "432 1328 816" "classname" "light" } { "classname" "light" "origin" "696 1112 816" "light" "300" } { "classname" "light" "origin" "704 -80 960" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "818 18 948" "light" "200" } { "origin" "586 18 948" "classname" "light_torch_small_walltorch" "light" "200" } { "light" "200" "origin" "688 496 880" "classname" "light" } { "origin" "489 483 1356" "classname" "light_flame_large_yellow" } { "light" "200" "origin" "704 -120 1360" "classname" "light" } { "classname" "light" "origin" "1216 936 1560" "light" "200" } { "origin" "1294 826 1576" "classname" "light_flame_large_yellow" } { "sounds" "1" "targetname" "t1" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*3" } { "angle" "0" "wait" "-1" "classname" "func_door" "model" "*4" } { "target" "t1" "classname" "trigger_once" "model" "*5" } { "map" "e1m5" "classname" "trigger_changelevel" "model" "*6" } { "wait" "-1" "angle" "0" "classname" "func_door" "speed" "50" "model" "*7" } { "classname" "info_player_start" "origin" "-256 2272 1240" "angle" "270" } { "targetname" "t23" "classname" "func_door" "angle" "180" "wait" "-1" "speed" "50" "sounds" "3" "model" "*8" } { "classname" "light" "origin" "696 704 820" } { "classname" "light" "origin" "704 776 672" "light" "200" } { "classname" "light" "origin" "360 904 520" "light" "200" } { "origin" "704 856 400" "classname" "light" "light" "200" } { "classname" "light" "origin" "944 880 416" "light" "150" } { "origin" "1056 1176 424" "classname" "light" "light" "200" } { "classname" "light" "origin" "1096 1408 360" } { "classname" "light" "origin" "416 1696 360" } { "origin" "328 1368 360" "classname" "light" "light" "200" } { "light" "200 " "classname" "light" "origin" "696 752 896" } { "light" "250" "origin" "798 1850 1024" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "642 1850 1024" "light" "250" } { "light" "200 " "origin" "700 1364 952" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "1094 1494 1064" } { "origin" "324 1104 1064" "classname" "light_flame_large_yellow" } { "light" "200 " "origin" "704 1660 952" "classname" "light" } { "sounds" "3" "classname" "func_door" "angle" "180" "wait" "-1" "targetname" "t2" "model" "*9" } { "sounds" "3" "classname" "func_door" "wait" "-1" "angle" "0" "targetname" "t4" "model" "*10" } { "classname" "trigger_once" "targetname" "t4" "target" "t7" "model" "*11" } { "classname" "trigger_once" "targetname" "t2" "target" "t7" "model" "*12" } { "dmg" "90" "speed" "200" "classname" "func_train" "target" "t5" "targetname" "t8" "model" "*13" } { "classname" "path_corner" "origin" "-359 1528 1316" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "-359 1528 880" "targetname" "t6" "target" "t5" "wait" "-1" } { "classname" "trigger_counter" "targetname" "t7" "target" "t8" "count" "2" "model" "*14" } { "targetname" "t11" "origin" "-96 1640 1256" "classname" "info_null" } { "targetname" "t9" "origin" "-416 1640 1256" "classname" "info_null" } { "light" "400" "target" "t9" "origin" "-396 1640 1256" "classname" "light" } { "light" "400" "target" "t11" "origin" "-116 1640 1256" "classname" "light" } { "classname" "light" "origin" "-328 1564 1532" } { "classname" "light_flame_small_yellow" "origin" "-88 1640 1514" } { "origin" "-424 1640 1514" "classname" "light_flame_small_yellow" } { "origin" "-248 1464 1154" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "-256 1808 1046" } { "light" "200" "origin" "-164 1732 1268" "classname" "light" } { "classname" "light" "origin" "-348 1732 1268" "light" "200" } { "light" "150" "origin" "-248 1500 1056" "classname" "light" } { "light" "150" "origin" "-256 1772 956" "classname" "light" } { "classname" "light" "origin" "-128 1636 920" "light" "150" } { "light" "150" "origin" "-124 1640 920" "classname" "light" } { "classname" "light" "origin" "-172 1524 920" "light" "150" } { "light" "150" "origin" "-284 1516 920" "classname" "light" } { "classname" "light" "origin" "-360 1580 920" "light" "150" } { "light" "75" "origin" "-360 1700 920" "classname" "light" } { "classname" "light" "origin" "72 1632 928" "light" "125" } { "light" "150" "origin" "80 1488 928" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "158 1308 1064" } { "classname" "light" "origin" "-192 1688 1380" "light" "100" } { "light" "100" "origin" "-192 1592 1380" "classname" "light" } { "classname" "light" "origin" "-320 1592 1380" "light" "100" } { "light" "100" "origin" "-320 1688 1380" "classname" "light" } { "classname" "light" "origin" "-384 1640 1452" "light" "125" } { "classname" "light" "origin" "-112 1640 1452" "light" "125" } { "light" "200" "origin" "-248 1504 1336" "classname" "light" } { "classname" "light" "origin" "-128 1640 1336" "light" "200" } { "light" "200" "origin" "-384 1640 1336" "classname" "light" } { "classname" "light" "origin" "696 1608 816" "light" "300" } { "light" "200" "classname" "light" "origin" "888 1328 424" } { "classname" "light" "origin" "160 1352 960" "light" "150" } { "light" "150" "origin" "368 1104 1000" "classname" "light" } { "classname" "light" "origin" "1048 1504 1000" "light" "150" } { "classname" "light" "origin" "992 992 1048" "light" "150" } { "classname" "light" "origin" "48 1384 1008" "light" "100" } { "light" "150" "origin" "1080 1144 1048" "classname" "light" } { "classname" "light" "origin" "968 824 976" "light" "150" } { "classname" "light" "origin" "896 1328 1000" "light" "150" } { "classname" "light" "origin" "368 1616 1000" "light" "175" } { "classname" "light" "origin" "256 1496 824" "light" "150" } { "light" "150" "origin" "256 1352 824" "classname" "light" } { "classname" "light" "origin" "856 1368 536" "light" "200" } { "light" "150" "origin" "552 1360 536" "classname" "light" } { "classname" "light" "origin" "872 1552 1056" "light" "150" } { "classname" "light" "origin" "1032 1056 904" "light" "150" } { "light" "150" "origin" "1080 1184 904" "classname" "light" } { "classname" "light" "origin" "864 848 904" "light" "150" } { "classname" "light" "origin" "312 1496 1016" "light" "175" } { "light" "200" "origin" "704 1368 808" "classname" "light" } { "light" "150" "origin" "464 816 904" "classname" "light" } { "light" "200" "origin" "944 888 800" "classname" "light" } { "light" "150" "origin" "888 1112 728" "classname" "light" } { "light" "175" "origin" "1008 1504 728" "classname" "light" } { "light" "200" "origin" "720 1848 1200" "classname" "light" } { "light" "200" "origin" "704 888 672" "classname" "light" } { "light" "175" "origin" "512 1456 1040" "classname" "light" } { "light" "150" "origin" "440 840 380" "classname" "light" } { "light" "150" "origin" "720 1848 1028" "classname" "light" } { "light" "150" "origin" "720 1936 1024" "classname" "light" } { "origin" "544 2128 984" "classname" "light" "light" "200" } { "light" "200" "origin" "712 1912 576" "classname" "light" } { "light" "300" "origin" "720 2544 856" "classname" "light" } { "light" "200" "origin" "888 2048 592" "classname" "light" } { "origin" "704 2496 1128" "classname" "light" } { "origin" "512 2048 976" "classname" "light" "light" "150" } { "origin" "952 2328 528" "classname" "light" "light" "200" } { "classname" "light" "origin" "700 2760 808" "light" "200" } { "classname" "light" "origin" "700 2800 616" "light" "200" } { "classname" "light" "origin" "584 2780 584" "light" "175" } { "light" "175" "origin" "808 2780 584" "classname" "light" } { "sounds" "3" "wait" "-1" "targetname" "t29" "classname" "func_door" "angle" "270" "model" "*15" } { "message" "This door is opened elsewhere..." "wait" "-1" "classname" "func_door" "angle" "90" "model" "*16" } { "classname" "light" "origin" "424 2304 1000" "light" "200" } { "light" "300" "origin" "696 2880 1062" "classname" "light_flame_small_yellow" } { "light" "200" "classname" "light" "origin" "864 2128 984" } { "classname" "light_flame_large_yellow" "origin" "702 2154 1228" "light" "0" } { "classname" "light" "origin" "832 2008 1136" "light" "200" } { "classname" "light" "origin" "584 2008 1136" "light" "200" } { "light" "200" "origin" "272 2016 1136" "classname" "light" } { "classname" "light" "origin" "272 2320 1136" "light" "150" } { "light" "150" "origin" "1104 2408 984" "classname" "light" } { "sounds" "2" "classname" "func_plat" "wait" "4" "model" "*17" } { "classname" "light" "origin" "700 2844 996" "light" "200" } { "classname" "light" "origin" "704 2216 1252" } { "origin" "936 2304 1252" "classname" "light" } { "classname" "light" "origin" "936 2536 1252" } { "light" "300" "classname" "light" "origin" "488 2536 1252" } { "origin" "488 2304 1252" "classname" "light" "light" "300" } { "light" "0" "origin" "998 2306 1228" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "998 2534 1228" "light" "0" } { "light" "0" "origin" "426 2534 1228" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "426 2306 1228" "light" "0" } { "classname" "light" "origin" "704 2152 984" "light" "200" } { "classname" "light_flame_small_yellow" "origin" "1160 2400 1038" "light" "250" } { "origin" "840 2536 630" "classname" "light_flame_small_yellow" "light" "250" } { "classname" "light_flame_small_yellow" "origin" "584 2544 630" "light" "250" } { "light" "250" "origin" "408 2304 694" "classname" "light_flame_small_yellow" } { "light" "200" "classname" "light" "origin" "960 2632 528" } { "classname" "light" "origin" "960 2480 528" "light" "150" } { "classname" "light" "origin" "456 2304 624" "light" "175" } { "classname" "light" "origin" "704 2416 576" "light" "250" } { "light" "150" "origin" "728 2184 528" "classname" "light" } { "classname" "light" "origin" "512 2176 528" "light" "150" } { "classname" "light" "origin" "832 2336 656" "light" "175" } { "light" "175" "origin" "592 2336 656" "classname" "light" } { "classname" "light" "origin" "808 2584 576" "light" "150" } { "light" "150" "origin" "616 2576 576" "classname" "light" } { "classname" "light_flame_small_yellow" "origin" "488 2712 694" "light" "250" } { "classname" "light" "origin" "488 2624 608" "light" "175" } { "classname" "light" "origin" "480 2464 608" "light" "175" } { "light" "250" "origin" "184 2184 1038" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "512 2096 1038" "light" "250" } { "classname" "light" "origin" "224 2184 976" "light" "150" } { "classname" "light" "origin" "848 2024 992" "light" "200" } { "classname" "light" "origin" "256 1992 1000" "light" "150" } { "classname" "light" "origin" "272 2376 1000" "light" "200" } { "classname" "light" "origin" "1112 2208 1032" "light" "150" } { "light" "0" "origin" "698 2860 1228" "classname" "light_flame_large_yellow" } { "origin" "700 2808 1252" "classname" "light" } { "light" "250" "origin" "472 2632 1062" "classname" "light" } { "classname" "light" "origin" "952 2632 1062" "light" "250" } { "light" "150" "origin" "952 2424 894" "classname" "light" } { "classname" "light" "origin" "480 2424 894" "light" "150" } { "light" "150" "origin" "896 2296 966" "classname" "light" } { "classname" "light" "origin" "704 2304 966" "light" "150" } { "light" "150" "origin" "552 2304 966" "classname" "light" } { "light" "250" "origin" "704 2184 406" "classname" "light" } { "light" "150" "origin" "712 2000 406" "classname" "light" } { "light" "200" "origin" "504 2224 400" "classname" "light" } { "light" "200" "origin" "960 2576 400" "classname" "light" } { "light" "150" "origin" "960 2400 400" "classname" "light" } { "light" "150" "origin" "808 1112 592" "classname" "light" } { "classname" "light" "origin" "600 1112 592" "light" "150" } { "light" "175" "origin" "1016 128 936" "classname" "light" } { "classname" "light" "origin" "392 128 936" "light" "175" } { "light" "150" "origin" "848 -64 1304" "classname" "light" } { "classname" "light" "origin" "560 -64 1304" "light" "150" } { "light" "175" "origin" "1248 832 1496" "classname" "light" } { "light" "150" "origin" "1096 872 1496" "classname" "light" } { "light" "150" "origin" "896 2208 976" "classname" "light" } { "classname" "light" "origin" "1096 200 1512" "light" "350" } { "light" "350" "origin" "264 192 1512" "classname" "light" } { "light" "175" "origin" "488 448 1264" "classname" "light" } { "origin" "1048 728 1456" "classname" "light" "light" "200" } { "light" "125" "origin" "1328 928 1448" "classname" "light" } { "light" "225" "origin" "696 672 1320" "classname" "light" } { "origin" "816 -56 1640" "classname" "light" } { "classname" "light" "origin" "584 -56 1640" } { "light" "175" "origin" "880 96 1376" "classname" "light" } { "classname" "light" "origin" "528 96 1376" "light" "175" } { "light" "200" "origin" "960 344 1072" "classname" "light" } { "classname" "light" "origin" "1120 264 1072" "light" "200" } { "light" "175" "origin" "1208 96 1016" "classname" "light" } { "light" "175" "origin" "1024 360 968" "classname" "light" } { "classname" "light" "origin" "328 336 968" "light" "150" } { "classname" "light" "origin" "416 424 1072" "light" "200" } { "light" "200" "origin" "296 256 1072" "classname" "light" } { "light" "150" "origin" "704 48 1040" "classname" "light" } { "light" "175" "origin" "384 464 976" "classname" "light" } { "classname" "light" "origin" "224 264 976" "light" "150" } { "light" "150" "origin" "952 2192 416" "classname" "light" } { "classname" "light" "origin" "1040 -464 1016" "light" "150" } { "sounds" "2" "spawnflags" "1" "classname" "func_plat" "model" "*18" } { "light" "250" "origin" "1072 -272 1262" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "1024 -272 1200" "light" "150" } { "light" "200" "origin" "624 -240 1328" "classname" "light" } { "light" "175" "origin" "1080 -624 1168" "classname" "light" } { "origin" "456 -576 1230" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "504 -576 1168" "light" "175" } { "origin" "624 -448 924" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "624 -704 924" } { "light" "125" "origin" "664 -448 880" "classname" "light" } { "classname" "light" "origin" "624 -488 880" "light" "125" } { "light" "125" "origin" "584 -448 880" "classname" "light" } { "classname" "light" "origin" "624 -408 880" "light" "125" } { "light" "125" "origin" "624 -664 880" "classname" "light" } { "classname" "light" "origin" "664 -704 880" "light" "125" } { "light" "125" "origin" "624 -744 880" "classname" "light" } { "classname" "light" "origin" "584 -704 880" "light" "125" } { "light" "250" "origin" "296 -96 968" "classname" "light" } { "light" "250" "origin" "1112 -96 968" "classname" "light" } { "light" "175" "origin" "1056 -224 968" "classname" "light" } { "light" "500" "origin" "-264 2120 1504" "classname" "light" } { "spawnflags" "2064" "angle" "0" "classname" "func_door" "wait" "-1" "model" "*19" } { "sounds" "3" "classname" "func_door" "angle" "180" "spawnflags" "2064" "wait" "-1" "model" "*20" } { "light" "200" "origin" "704 32 952" "classname" "light" } { "target" "t101" "spawnflags" "256" "targetname" "t23" "angle" "90" "origin" "-248 1560 1224" "classname" "monster_wizard" } { "target" "t23" "classname" "trigger_once" "model" "*21" } { "origin" "-280 1560 1348" "classname" "item_armor2" } { "origin" "-488 2112 1220" "classname" "item_health" } { "classname" "item_health" "origin" "-488 2064 1220" } { "spawnflags" "1536" "origin" "-272 1784 1156" "classname" "item_shells" } { "spawnflags" "256" "target" "t25" "targetname" "t24" "origin" "888 1640 1028" "classname" "path_corner" } { "spawnflags" "256" "target" "t24" "targetname" "t25" "classname" "path_corner" "origin" "624 1264 1028" } { "spawnflags" "256" "target" "t24" "origin" "928 1672 1028" "classname" "monster_wizard" } { "spawnflags" "2304" "target" "t26" "classname" "trigger_once" "model" "*22" } { "target" "t27" "targetname" "t28" "origin" "568 2040 928" "classname" "path_corner" } { "target" "t28" "targetname" "t27" "classname" "path_corner" "origin" "368 2044 928" } { "target" "t27" "origin" "472 2040 944" "classname" "monster_ogre" "spawnflags" "1" } { "sounds" "2" "target" "t29" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*23" } { "sounds" "3" "angle" "180" "classname" "func_door" "model" "*24" } { "angle" "0" "classname" "func_door" "model" "*25" } { "light" "175" "origin" "1112 2520 964" "classname" "light" } { "origin" "104 1308 892" "classname" "item_health" } { "spawnflags" "2048" "origin" "704 1344 936" "classname" "item_key1" "sounds" "1" } { "target" "t34" "angle" "180" "origin" "920 2040 544" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t35" "targetname" "t34" "origin" "864 2044 528" "classname" "path_corner" } { "target" "t37" "targetname" "t35" "classname" "path_corner" "origin" "704 2048 528" } { "target" "t34" "targetname" "t36" "origin" "704 2048 528" "classname" "path_corner" } { "target" "t36" "targetname" "t37" "classname" "path_corner" "origin" "704 1808 528" } { "targetname" "t38" "angle" "270" "origin" "456 2476 544" "classname" "monster_ogre" } { "target" "t38" "classname" "trigger_once" "model" "*26" } { "targetname" "t29" "angle" "0" "origin" "336 2272 952" "classname" "monster_knight" "spawnflags" "768" } { "targetname" "t39" "spawnflags" "1" "wait" "-1" "angle" "-2" "classname" "func_door" "sounds" "1" "model" "*27" } { "targetname" "t39" "angle" "270" "origin" "712 2540 448" "classname" "monster_ogre" } { "target" "t39" "classname" "trigger_once" "model" "*28" } { "classname" "light" "origin" "712 2544 440" "light" "200" } { "classname" "item_health" "origin" "1064 2184 920" "spawnflags" "1024" } { "spawnflags" "1" "origin" "1128 2184 920" "classname" "item_health" } { "classname" "item_spikes" "origin" "816 2840 920" } { "origin" "816 2800 920" "classname" "item_spikes" } { "spawnflags" "256" "classname" "monster_wizard" "origin" "1656 1496 968" "angle" "180" "target" "t41" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t40" "targetname" "t39" "model" "*29" } { "classname" "info_teleport_destination" "origin" "984 1496 1000" "angle" "180" "targetname" "t40" } { "spawnflags" "256" "classname" "path_corner" "origin" "912 1496 1000" "targetname" "t41" "target" "t42" } { "spawnflags" "256" "origin" "528 1368 1000" "classname" "path_corner" "targetname" "t42" "target" "t41" } { "classname" "item_health" "origin" "408 2640 520" } { "classname" "item_shells" "origin" "456 2672 520" "spawnflags" "1" } { "angle" "0" "origin" "80 864 968" "classname" "monster_wizard" "target" "t44" } { "targetname" "t119" "spawnflags" "2" "classname" "trigger_teleport" "target" "t45" "model" "*30" } { "classname" "info_teleport_destination" "origin" "432 856 952" "angle" "45" "targetname" "t45" } { "classname" "path_corner" "origin" "496 872 952" "target" "t43" "targetname" "t44" } { "origin" "872 1056 952" "classname" "path_corner" "targetname" "t43" "target" "t44" } { "classname" "trigger_once" "spawnflags" "1792" "target" "t39" "model" "*31" } { "spawnflags" "1024" "classname" "monster_knight" "origin" "1168 56 904" "angle" "135" "target" "t49" "targetname" "t67" } { "classname" "monster_ogre" "origin" "1800 224 920" "angle" "180" "target" "t116" "spawnflags" "256" } { "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t49" "lip" "-24" "model" "*32" } { "wait" "-1" "angle" "-1" "classname" "func_door" "spawnflags" "1" "targetname" "t39" "lip" "-24" "model" "*33" } { "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t29" "lip" "-24" "model" "*34" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t46" "model" "*35" } { "classname" "info_teleport_destination" "origin" "1104 232 880" "angle" "180" "targetname" "t46" } { "classname" "path_corner" "origin" "1064 256 880" "target" "t47" "targetname" "t48" "spawnflags" "256" } { "origin" "312 232 880" "classname" "path_corner" "targetname" "t47" "target" "t48" "spawnflags" "256" } { "classname" "info_teleport_destination" "origin" "704 -40 1256" "angle" "90" "targetname" "t50" } { "classname" "trigger_once" "target" "t52" "model" "*36" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t50" "targetname" "t52" "model" "*37" } { "angle" "90" "origin" "570 -898 1300" "classname" "monster_wizard" "targetname" "t52" } { "classname" "item_shells" "origin" "216 120 880" "spawnflags" "1" } { "classname" "item_health" "origin" "192 232 880" } { "origin" "192 192 880" "classname" "item_health" "spawnflags" "1024" } { "classname" "item_shells" "origin" "-216 1464 888" } { "classname" "item_health" "origin" "816 1160 512" "spawnflags" "1024" } { "spawnflags" "1" "origin" "816 1120 512" "classname" "item_health" } { "classname" "monster_wizard" "origin" "944 840 956" "angle" "135" "target" "t53" "targetname" "t64" } { "classname" "trigger_once" "target" "t64" "model" "*38" } { "classname" "monster_knight" "origin" "704 392 1280" "angle" "270" "target" "t65" "spawnflags" "1" } { "classname" "path_corner" "origin" "704 208 1264" "targetname" "t65" "target" "t66" } { "origin" "704 496 1264" "classname" "path_corner" "targetname" "t66" "target" "t65" } { "classname" "trigger_once" "target" "t67" "model" "*39" } { "sounds" "1" "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t72" "model" "*40" } { "sounds" "1" "classname" "func_door" "wait" "-1" "angle" "-2" "targetname" "t72" "model" "*41" } { "classname" "trigger_once" "target" "t72" "model" "*42" } { "classname" "info_null" "origin" "852 -580 820" "targetname" "t73" } { "classname" "light" "origin" "856 -584 936" "light" "400" "target" "t73" } { "classname" "light" "origin" "920 -448 744" "light" "150" } { "light" "150" "origin" "760 -448 744" "classname" "light" } { "classname" "light" "origin" "552 -424 744" "light" "150" } { "light" "150" "origin" "560 -728 744" "classname" "light" } { "classname" "light" "origin" "776 -712 744" "light" "150" } { "light" "150" "origin" "936 -712 744" "classname" "light" } { "classname" "path_corner" "origin" "652 -576 952" "targetname" "t75" "target" "t74" } { "origin" "908 -576 952" "classname" "path_corner" "targetname" "t74" "target" "t75" } { "classname" "monster_ogre" "origin" "816 -260 952" "angle" "270" "targetname" "t72" } { "classname" "monster_ogre" "origin" "724 -260 952" "angle" "270" "targetname" "t72" "spawnflags" "256" } { "classname" "item_health" "origin" "632 -548 820" "spawnflags" "3072" } { "origin" "672 -548 820" "classname" "item_health" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t76" "model" "*43" } { "sounds" "1" "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t76" "model" "*44" } { "light" "150" "origin" "1040 -712 1016" "classname" "light" } { "origin" "1112 -576 942" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "1064 -576 896" "light" "150" } { "classname" "light" "origin" "888 -80 968" "light" "175" } { "light" "175" "origin" "512 -80 968" "classname" "light" } { "classname" "item_armor2" "origin" "1184 -96 920" } { "classname" "monster_ogre" "origin" "392 8 912" "angle" "315" "targetname" "t77" "spawnflags" "256" } { "classname" "trigger_once" "target" "t77" "model" "*45" } { "classname" "item_health" "origin" "336 -224 888" "spawnflags" "1" } { "classname" "item_spikes" "origin" "968 16 888" "spawnflags" "1" } { "classname" "item_health" "origin" "560 2808 516" "spawnflags" "1" } { "classname" "path_corner" "origin" "1056 -384 824" "targetname" "t78" "target" "t79" "spawnflags" "256" } { "origin" "1056 -736 824" "classname" "path_corner" "targetname" "t79" "target" "t78" "spawnflags" "256" } { "classname" "monster_ogre" "origin" "1064 -656 840" "angle" "90" "target" "t78" "spawnflags" "257" } { "angle" "90" "origin" "848 -880 952" "classname" "monster_ogre" "targetname" "t72" } { "classname" "item_shells" "origin" "1160 16 1248" } { "classname" "item_health" "origin" "280 64 1248" } { "classname" "item_rockets" "origin" "648 -256 928" "spawnflags" "1025" } { "classname" "item_spikes" "origin" "648 -304 1248" } { "origin" "696 -304 1248" "classname" "item_spikes" } { "classname" "light_flame_small_yellow" "origin" "768 -352 1230" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*46" } { "target" "t83" "classname" "trigger_multiple" "wait" ".8" "model" "*47" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*48" } { "target" "t83" "classname" "trigger_multiple" "wait" ".8" "model" "*49" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*50" } { "targetname" "t83" "classname" "trap_spikeshooter" "origin" "1108 -576 1140" "spawnflags" "1" "angle" "180" } { "targetname" "t83" "angle" "90" "spawnflags" "1" "origin" "768 -796 1140" "classname" "trap_spikeshooter" } { "origin" "1112 -576 1230" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "768 -800 1230" } { "classname" "light" "origin" "712 -756 1168" "light" "175" } { "light" "175" "origin" "768 -424 1168" "classname" "light" } { "light" "175" "origin" "888 -744 956" "classname" "light" } { "classname" "light" "origin" "888 -408 956" "light" "175" } { "origin" "384 -224 888" "classname" "item_shells" } { "origin" "584 1784 920" "classname" "item_health" } { "origin" "832 2064 920" "classname" "item_shells" } { "target" "t72" "classname" "trigger_once" "model" "*51" } { "target" "t85" "targetname" "t84" "origin" "1560 216 896" "classname" "path_corner" } { "target" "t48" "targetname" "t85" "classname" "path_corner" "origin" "1456 216 896" } { "origin" "704 1368 516" "classname" "weapon_supernailgun" } { "spawnflags" "1" "origin" "184 1928 920" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "656 1816 528" "spawnflags" "768" } { "classname" "item_shells" "origin" "1072 -800 820" "spawnflags" "1024" } { "classname" "monster_ogre" "origin" "840 -40 1276" "angle" "180" "targetname" "t86" "spawnflags" "768" } { "classname" "trigger_once" "target" "t86" "model" "*52" } { "classname" "light" "origin" "472 -576 876" "light" "150" } { "classname" "item_shells" "origin" "656 680 1256" "spawnflags" "1536" } { "angle" "270" "origin" "880 2224 536" "classname" "monster_knight" "spawnflags" "256" } { "angle" "180" "origin" "1112 2424 944" "classname" "monster_ogre" "spawnflags" "1281" } { "targetname" "t88" "target" "t87" "origin" "360 384 880" "classname" "path_corner" "spawnflags" "1280" } { "target" "t88" "targetname" "t87" "classname" "path_corner" "origin" "504 160 880" "spawnflags" "1280" } { "target" "t87" "angle" "315" "origin" "384 320 896" "classname" "monster_knight" "spawnflags" "1280" } { "spawnflags" "257" "targetname" "t86" "angle" "0" "origin" "376 120 1272" "classname" "monster_ogre" } { "origin" "776 1368 916" "classname" "item_shells" "spawnflags" "1024" } { "classname" "item_spikes" "origin" "184 1968 920" "spawnflags" "1" } { "classname" "monster_wizard" "origin" "312 936 944" "angle" "45" "spawnflags" "769" } { "classname" "monster_knight" "origin" "704 -80 908" "angle" "90" } { "angle" "0" "origin" "568 -56 1276" "classname" "monster_ogre" "targetname" "t86" "spawnflags" "768" } { "spawnflags" "1536" "targetname" "t90" "target" "t89" "origin" "720 1696 924" "classname" "path_corner" } { "spawnflags" "1536" "target" "t90" "targetname" "t89" "classname" "path_corner" "origin" "720 1416 924" } { "spawnflags" "1537" "target" "t90" "origin" "704 1784 948" "classname" "monster_ogre" } { "classname" "func_door_secret" "angle" "0" "spawnflags" "1" "targetname" "t91" "model" "*53" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*54" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*55" } { "classname" "func_button" "wait" "-1" "angle" "-2" "target" "t92" "model" "*56" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*57" } { "classname" "func_button" "wait" "-1" "angle" "-2" "target" "t92" "model" "*58" } { "classname" "trigger_counter" "count" "5" "target" "t91" "targetname" "t92" "model" "*59" } { "classname" "light" "origin" "680 -920 1144" "light" "150" } { "classname" "item_spikes" "origin" "752 -876 928" "spawnflags" "1" } { "spawnflags" "3" "angle" "0" "classname" "func_door_secret" "targetname" "t91" "model" "*60" } { "light" "150" "origin" "680 -256 1144" "classname" "light" } { "classname" "trigger_once" "spawnflags" "1792" "target" "t72" "model" "*61" } { "classname" "trigger_secret" "sounds" "1" "targetname" "t8" "model" "*62" } { "angle" "270" "origin" "704 624 1280" "classname" "monster_knight" "spawnflags" "1" } { "angle" "225" "origin" "1016 -440 1128" "classname" "monster_knight" } { "angle" "180" "origin" "1024 -728 1128" "classname" "monster_knight" } { "spawnflags" "256" "angle" "180" "origin" "1008 -568 1128" "classname" "monster_knight" } { "spawnflags" "256" "classname" "monster_knight" "origin" "304 2312 952" "angle" "0" "targetname" "t29" } { "spawnflags" "1025" "classname" "monster_knight" "origin" "272 136 896" "angle" "45" } { "classname" "monster_wizard" "origin" "784 -576 960" "angle" "0" "target" "t74" "spawnflags" "1" } { "classname" "item_health" "origin" "732 -936 928" } { "origin" "772 -936 928" "classname" "item_health" } { "spawnflags" "256" "classname" "monster_knight" "origin" "704 -248 1272" "angle" "0" } { "classname" "path_corner" "origin" "1328 928 1396" "targetname" "t93" "target" "t94" "spawnflags" "512" } { "origin" "1176 928 1396" "classname" "path_corner" "target" "t93" "targetname" "t94" "spawnflags" "512" } { "classname" "monster_knight" "origin" "1192 884 1412" "angle" "0" "target" "t93" "spawnflags" "513" } { "classname" "monster_knight" "origin" "704 2376 944" "angle" "90" } { "classname" "monster_knight" "origin" "888 2312 944" "angle" "180" "targetname" "t95" } { "angle" "0" "origin" "512 2304 944" "classname" "monster_knight" "targetname" "t95" "spawnflags" "768" } { "classname" "trigger_once" "target" "t95" "model" "*63" } { "spawnflags" "256" "angle" "315" "origin" "728 2312 536" "classname" "monster_knight" } { "light" "200" "origin" "1296 1528 936" "classname" "light" } { "light" "250" "origin" "1432 1360 982" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "1400 1360 920" "classname" "light" } { "light" "200" "origin" "1248 1344 680" "classname" "light" } { "lip" "-384" "wait" "-1" "angle" "90" "classname" "func_door" "targetname" "t98" "model" "*64" } { "light" "150" "origin" "1152 1328 584" "classname" "light" } { "origin" "1376 1480 864" "classname" "item_health" } { "sounds" "1" "classname" "trigger_secret" "model" "*65" } { "classname" "func_button" "sounds" "1" "angle" "0" "wait" "-1" "target" "t97" "model" "*66" } { "classname" "func_button" "wait" "-1" "angle" "0" "sounds" "1" "target" "t97" "model" "*67" } { "classname" "trigger_counter" "targetname" "t97" "target" "t98" "model" "*68" } { "classname" "light" "origin" "880 -888 968" "light" "150" } { "light" "150" "origin" "880 -264 968" "classname" "light" } { "angle" "180" "origin" "1112 2344 944" "classname" "monster_ogre" "spawnflags" "769" } { "angle" "270" "origin" "1120 880 1412" "classname" "monster_ogre" "spawnflags" "257" } { "map" "e1m8" "classname" "trigger_changelevel" "model" "*69" } { "light" "175" "origin" "824 -756 1168" "classname" "light" } { "classname" "light" "origin" "1080 -528 1168" "light" "175" } { "classname" "monster_wizard" "origin" "672 -392 1024" "angle" "315" "spawnflags" "257" } { "classname" "monster_knight" "origin" "1008 -656 1128" "angle" "180" "spawnflags" "768" } { "origin" "520 1064 440" "classname" "air_bubbles" } { "classname" "item_spikes" "origin" "16 1432 892" } { "classname" "trigger_once" "message" "A secret cave has opened..." "targetname" "t98" "model" "*70" } { "target" "t4" "health" "1" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*71" } { "target" "t2" "health" "1" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*72" } { "target" "t49" "spawnflags" "769" "angle" "135" "origin" "1208 128 904" "classname" "monster_demon1" } { "spawnflags" "769" "angle" "45" "origin" "288 160 896" "classname" "monster_demon1" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "692 -884 952" "angle" "90" } { "classname" "monster_ogre" "origin" "-312 1648 1372" "angle" "90" "targetname" "t23" "spawnflags" "768" } { "angle" "90" "origin" "-192 1648 1372" "classname" "monster_ogre" "targetname" "t23" "spawnflags" "768" } { "classname" "monster_ogre" "origin" "704 1288 540" "angle" "270" "spawnflags" "768" } { "targetname" "t101" "target" "t106" "spawnflags" "770" "classname" "trigger_teleport" "model" "*73" } { "spawnflags" "768" "targetname" "t101" "angle" "270" "origin" "-256 2424 1288" "classname" "monster_wizard" } { "targetname" "t101" "origin" "-248 2440 1280" "classname" "trigger_relay" } { "targetname" "t29" "spawnflags" "256" "angle" "0" "origin" "144 2648 1024" "classname" "monster_wizard" } { "targetname" "t29" "spawnflags" "768" "classname" "monster_wizard" "origin" "144 2592 1024" "angle" "0" } { "targetname" "t29" "spawnflags" "768" "angle" "0" "origin" "144 2536 1024" "classname" "monster_wizard" } { "targetname" "t29" "target" "t102" "spawnflags" "258" "classname" "trigger_teleport" "model" "*74" } { "targetname" "t29" "target" "t103" "spawnflags" "770" "classname" "trigger_teleport" "model" "*75" } { "targetname" "t29" "target" "t104" "spawnflags" "770" "classname" "trigger_teleport" "model" "*76" } { "angle" "270" "targetname" "t102" "spawnflags" "256" "origin" "704 2656 1008" "classname" "info_teleport_destination" } { "angle" "270" "targetname" "t103" "spawnflags" "768" "classname" "info_teleport_destination" "origin" "920 2520 1008" } { "angle" "0" "targetname" "t104" "spawnflags" "768" "origin" "592 2192 1008" "classname" "info_teleport_destination" } { "sounds" "1" "classname" "func_door" "angle" "0" "wait" "-1" "speed" "150" "targetname" "t105" "model" "*77" } { "classname" "monster_demon1" "origin" "1056 -880 1128" "angle" "90" "spawnflags" "768" "targetname" "t105" } { "classname" "trigger_once" "spawnflags" "768" "target" "t105" "model" "*78" } { "classname" "light" "origin" "1056 -920 1184" "light" "125" } { "classname" "trigger_relay" "origin" "1104 -864 1120" "target" "t105" } { "classname" "monster_ogre" "origin" "1120 768 1416" "angle" "180" "spawnflags" "769" } { "classname" "air_bubbles" "origin" "884 1616 440" } { "targetname" "t106" "spawnflags" "768" "angle" "270" "origin" "-264 2232 1296" "classname" "info_teleport_destination" } { "classname" "path_corner" "origin" "568 1984 928" "targetname" "t107" "target" "t108" "spawnflags" "256" } { "origin" "424 1960 928" "classname" "path_corner" "target" "t107" "spawnflags" "256" "targetname" "t111" } { "classname" "path_corner" "origin" "704 2024 928" "targetname" "t108" "target" "t109" "spawnflags" "256" } { "origin" "712 1712 928" "classname" "path_corner" "targetname" "t109" "target" "t110" "spawnflags" "256" } { "classname" "path_corner" "origin" "712 1416 928" "targetname" "t110" "target" "t109" "spawnflags" "256" } { "classname" "func_door" "angle" "-2" "wait" "-1" "lip" "-24" "targetname" "t26" "spawnflags" "2304" "model" "*79" } { "classname" "monster_ogre" "origin" "240 2048 944" "angle" "0" "spawnflags" "257" "target" "t111" } { "target" "t23" "spawnflags" "1792" "classname" "trigger_once" "model" "*80" } { "classname" "monster_knight" "origin" "576 2768 536" "angle" "0" "spawnflags" "256" } { "spawnflags" "256" "angle" "180" "origin" "824 2776 536" "classname" "monster_knight" } { "classname" "monster_wizard" "origin" "704 -1032 1024" "angle" "90" "spawnflags" "256" "targetname" "t52" } { "angle" "90" "origin" "760 -1032 1024" "classname" "monster_wizard" "spawnflags" "768" "targetname" "t114" } { "classname" "monster_wizard" "origin" "816 -1032 1024" "angle" "90" "spawnflags" "768" "targetname" "t114" } { "targetname" "t52" "classname" "trigger_teleport" "spawnflags" "258" "target" "t112" "model" "*81" } { "classname" "trigger_teleport" "spawnflags" "770" "target" "t113" "targetname" "t114" "model" "*82" } { "targetname" "t114" "classname" "trigger_teleport" "spawnflags" "770" "target" "t115" "model" "*83" } { "classname" "info_teleport_destination" "origin" "896 224 1352" "angle" "135" "spawnflags" "256" "targetname" "t112" } { "classname" "info_teleport_destination" "origin" "488 1648 1016" "angle" "315" "spawnflags" "768" "targetname" "t113" } { "classname" "trigger_once" "spawnflags" "768" "target" "t114" "model" "*84" } { "classname" "info_teleport_destination" "origin" "800 904 928" "angle" "90" "spawnflags" "768" "targetname" "t115" } { "angle" "270" "origin" "-256 2232 1242" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "-256 2096 1218" "classname" "weapon_supershotgun" } { "angle" "270" "origin" "704 424 1266" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 2488 946" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 1968 546" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "704 104 898" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 1568 938" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "704 1344 912" "classname" "weapon_rocketlauncher" } { "angle" "0" "origin" "712 -576 840" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "944 -576 816" "classname" "weapon_nailgun" } { "angle" "180" "origin" "1064 -576 1128" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "696 584 1256" "classname" "weapon_grenadelauncher" } { "classname" "light" "origin" "316 804 780" "light" "150" } { "classname" "light" "origin" "316 804 644" "light" "75" } { "classname" "item_rockets" "origin" "298 710 706" "spawnflags" "1" } { "classname" "item_shells" "origin" "988 -928 1104" "spawnflags" "1" } { "classname" "item_health" "origin" "-56 2112 1220" "spawnflags" "3584" } { "classname" "item_health" "origin" "-56 2072 1220" "spawnflags" "2305" } { "spawnflags" "1" "origin" "584 2416 512" "classname" "item_spikes" } { "origin" "688 1392 516" "classname" "item_spikes" } { "classname" "item_artifact_invulnerability" "origin" "712 2312 948" "spawnflags" "1792" } { "origin" "32 1392 916" "classname" "item_artifact_envirosuit" } { "mangle" "26 310 0" "origin" "384 488 1552" "classname" "info_intermission" } { "light" "100" "origin" "800 1160 464" "classname" "light" } { "classname" "light" "origin" "608 1160 464" "light" "100" } { "light" "100" "origin" "604 1472 464" "classname" "light" } { "target" "t40" "classname" "trigger_teleport" "model" "*85" } { "mangle" "-20 75 0" "origin" "456 2144 568" "classname" "info_intermission" } { "mangle" "10 80 0" "origin" "464 1032 1000" "classname" "info_intermission" } { "mangle" "20 135 0" "origin" "1080 -752 1008" "classname" "info_intermission" } { "classname" "trigger_secret" "model" "*86" } { "classname" "path_corner" "origin" "1632 216 896" "targetname" "t116" "target" "t84" } { "classname" "item_spikes" "origin" "1200 48 872" "spawnflags" "1" } { "classname" "item_spikes" "origin" "928 2664 320" "spawnflags" "1" } { "classname" "item_shells" "origin" "1240 768 1384" "spawnflags" "1" } { "classname" "item_shells" "origin" "-88 2160 1224" "spawnflags" "2049" } { "classname" "info_player_coop" "origin" "-208 2272 1240" "angle" "270" } { "angle" "270" "origin" "-304 2272 1240" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-352 2272 1240" "angle" "270" } { "light" "200" "origin" "1288 1648 956" "classname" "light" } { "classname" "item_spikes" "origin" "-264 1464 888" } { "spawnflags" "1792" "origin" "1296 1488 888" "classname" "item_artifact_invisibility" } { "spawnflags" "1792" "classname" "func_wall" "model" "*87" } { "classname" "func_wall" "spawnflags" "1792" "model" "*88" } { "target" "t118" "targetname" "t117" "origin" "-176 1640 888" "classname" "path_corner" } { "targetname" "t118" "target" "t117" "classname" "path_corner" "origin" "-320 1640 888" } { "target" "t117" "origin" "-256 1632 904" "classname" "monster_knight" "spawnflags" "1" } { "origin" "1376 1424 864" "classname" "weapon_grenadelauncher" } { "spawnflags" "1" "targetname" "t120" "target" "t119" "classname" "trigger_counter" "model" "*89" } { "target" "t120" "targetname" "t53" "classname" "trigger_once" "model" "*90" } { "target" "t120" "targetname" "t39" "classname" "trigger_once" "model" "*91" } { "classname" "light" "origin" "480 2568 568" "light" "125" } { "origin" "162 1482 976" "classname" "ambient_drip" } { "origin" "786 1010 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "778 1210 584" } { "origin" "594 1202 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "602 1010 584" } { "origin" "786 1514 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "794 1698 584" } { "origin" "618 1690 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "618 1522 584" } { "origin" "698 1362 584" "classname" "ambient_drip" } { "origin" "714 1970 592" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "898 2170 592" } { "origin" "938 2346 592" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "682 2298 592" } { "origin" "458 2306 592" "classname" "ambient_drip" } { "origin" "458 1690 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "322 1506 880" } { "origin" "338 1226 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "466 1090 880" } { "origin" "394 882 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "674 810 880" } { "origin" "914 818 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "922 1034 880" } { "origin" "1082 1266 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "994 1442 880" } { "origin" "898 1714 880" "classname" "ambient_drip" } { "origin" "706 1362 1080" "classname" "ambient_drip" } { "origin" "1194 1522 1032" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1314 1354 1032" } { "origin" "442 354 920" "classname" "ambient_swamp1" } { "origin" "978 314 920" "classname" "ambient_swamp2" } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/default.cfg�����������������������������������������������������������0000644�0000000�0000000�00000003777�12327137640�016752� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// // load keybindings // // commands with a leading + will also be called for key up events with // the + changed to a - unbindall // // character controls // bind ALT +strafe bind , +moveleft bind a +moveleft bind . +moveright bind d +moveright bind DEL +lookdown bind PGDN +lookup bind END centerview bind e +moveup bind c +movedown bind SHIFT +speed bind CTRL +attack bind UPARROW +forward bind w +forward bind DOWNARROW +back bind s +back bind LEFTARROW +left bind RIGHTARROW +right bind SPACE +jump //bind ENTER +jump bind TAB +showscores bind 1 "impulse 1" bind 2 "impulse 2" bind 3 "impulse 3" bind 4 "impulse 4" bind 5 "impulse 5" bind 6 "impulse 6" bind 7 "impulse 7" bind 8 "impulse 8" bind 0 "impulse 0" bind / "impulse 10" // change weapon bind MWHEELDOWN "impulse 10" bind MWHEELUP "impulse 12" // zoom alias zoom_in "sensitivity 2;fov 90;wait;fov 70;wait;fov 50;wait;fov 30;wait;fov 10;wait;fov 5;bind F11 zoom_out" alias zoom_out "sensitivity 4;fov 5;wait;fov 10;wait;fov 30;wait;fov 50;wait;fov 70;wait;fov 90;bind F11 zoom_in; sensitivity 3" bind F11 zoom_in // Function keys bind F1 "help" bind F2 "menu_save" bind F3 "menu_load" bind F4 "menu_options" bind F5 "menu_multiplayer" bind F6 "echo Quicksaving...; wait; save quick" bind F9 "echo Quickloading...; wait; load quick" bind F10 "quit" bind F12 "screenshot" // mouse options bind \ +mlook // // client environment commands // bind PAUSE "pause" bind ESCAPE "togglemenu" bind ~ "toggleconsole" bind ` "toggleconsole" bind t "messagemode" bind + "sizeup" bind = "sizeup" bind - "sizedown" bind INS +klook // // mouse buttons // bind MOUSE1 +attack //bind MOUSE2 +forward bind MOUSE2 +jump //bind MOUSE3 +mlook // // default cvars // gamma 1.0 volume 0.7 sensitivity 3 //viewsize 100 viewsize 110 scr_conscale 1.6 scr_menuscale 1.6 scr_sbarscale 1.6 // default to mouse-look enabled +mlook �quakespasm-0.91.0/Misc/qs_pak/gfx/������������������������������������������������������������������0000755�0000000�0000000�00000000000�12646150016�015407� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/gfx/conback.lmp�������������������������������������������������������0000644�0000000�0000000�00001200010�12327137640�017517� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������€�����®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬¬­¬¬¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬­¬­¬¬¬¬¬¬«««¬«¬¬¬­¬¬¬¬¬­¬­¬¬­­¬¬­¬¬¬¬¬­¬¬­¬­¬­®®®®®®®®®¿111¿11¿¿1¿¿1¿¿¿1¿¿¿®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬­¬¬­¬¬­­­­¬¬­­¬¬¬¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬«­«««««¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬®®®®®®®®®®¿11¿1111111111¿¿¿1®®®®®®®®®­¬­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬¬¬­¬«¬««««¬¬¬¬¬¬­­¬¬¬¬­­¬¬¬¬¬¬­¬¬¬¬­­®®®®®®®®®¿¿¿¿¿¿1¿1111¿¿¿¿1¿¿¿¿®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬¬¬­­­¬­­¬¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬­­¬¬­­­¬¬¬¬¬¬­®®®®®®®®¿¿¿¿¿¿¿11111¿¿1¿1¿1®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬­¬¬­¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬«¬¬¬¬««­­¬­­­¬¬­­­¬¬¬­¬¬­¬­®®®®®¿¿¿11¿¿11111111¿1111111111®®®®®®®®®®®¬­®¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬­­­¬­¬¬¬­­­¬¬­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««¬¬¬¬­«¬¬¬¬¬¬­¬­¬­­¬¬¬­­¬¬¬¬¬­®®®®®®®®¿1111¿¿¿111111¿11111111¿®®®®®®®®®®®®®¬­­®­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬­¬¬­­¬¬¬¬­¬­¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬«­««¬¬¬«¬¬¬¬¬¬­¬­­¬­­¬¬­¬¬¬¬¬¬¬®®®®®¿1111¿¿¿¿1¿1111¿1¿1¿1¿¿¿¿®®®®®®®®®®¬¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬­¬­¬­¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬«¬¬¬¬¬««««¬¬¬¬¬¬¬¬¬¬­¬¬¬­­­¬¬¬¬¬®®®®®¿11¿1¿¿¿1¿¿11¿1¿¿¿¿®®®®®®®®®®¬¬®®¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬¬­­¬¬¬¬¬¬­­¬­­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬«««¬¬¬««««««¬«¬¬¬¬¬­¬¬¬¬¬¬­­­¬¬¬­¬¬¬­®®®®®¿¿111¿¿¿1¿¿¿11¿¿¿¿®®®®®®®­®®®®¬¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««¬­¬¬««««¬¬¬¬¬¬­­¬­¬¬¬­¬¬¬¬¬¬¬­¬­¬®®¿11¿¿¿1¿¿1¿¿¿1®®®®®­­¬­¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬¬­¬­¬­¬­¬¬­­¬­­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««¬¬¬«¬­¬­¬¬­¬­¬¬­¬­¬­¬­¬¬¬­­­­®®®®®1¿¿¿¿¿11¿¿¿¿¿¿¿1®®®®®®®®®­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬­¬¬¬¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬­­¬¬¬¬¬«¬¬¬¬¬¬­¬­¬­¬¬¬­­­­­¬¬¬¬¬­¬¬­¬­®­®®®¿¿¿¿1111111¿®®®®®®®®®®®®­­®­­­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬­¬¬¬­­¬­­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬­¬­­¬¬¬­¬¬¬¬¬¬¬¬­­¬­­®®¿¿111111¿¿¿¿¿®®®®®®®®®®®¬­¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬¬¬«¬¬«¬«««¬¬¬¬¬­­¬­¬¬¬¬¬¬­¬¬¬¬­¬¬¬®®®®®¿1¿1¿¿¿¿¿®®®®®®®®®®®®®­®­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­¬¬­¬¬­­¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬­¬¬«¬¬¬«««««¬¬¬­¬¬­¬¬¬¬¬¬¬¬­­­­­­¬¬­®®®®®11¿¿¿1¿®®®®®®®®®®®®®­®­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬¬¬­¬­¬¬­­­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«««¬««««¬¬­­¬¬¬­­¬¬­¬¬¬¬¬­¬­­¬¬®®®®®®®1¿®¿¿¿¿®®®®®®®®®®®®®®®®®®­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­¬­¬­¬¬¬­¬¬­¬¬­¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬­«««««¬««««««««««««««««­¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬­­¬¬¬¬¬­®®®®¿1¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬­¬¬¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­®­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬­¬¬¬¬¬¬¬¬«««««««««««««««««««««««¬«««««¬¬­¬¬¬­­¬¬­¬¬¬­¬¬¬¬¬¬­­­¬­¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬­¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««­¬­¬­­¬¬­¬¬­¬¬­­¬­­¬¬­¬­¬­¬®®¿®¿¿¿®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬­­¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬­¬¬¬­¬¬¬¬¬««¬¬¬¬¬¬¬¬¬¬¬«««¬«««««««««««««««««««¬«­¬­¬¬­¬¬­¬¬¬¬­¬­¬¬­¬¬¬¬¬¬­¬¬­¬¬®®®1¿®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬¬¬­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®¬­­­¬¬¬­¬­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬­«¬¬«««««««««¬««««««¬«¬¬­¬¬­­®¬­­¬¬¬­¬¬­­¬¬¬¬­¬¬­¬¬¬­¬­­­­®®¿¿¿®®®®®®®®®®®®®®®®®®­¬¬¬­¬¬¬¬¬­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬¬«««««««««««¬«««««««««««««­¬­¬¬¬¬¬­¬¬­­­¬¬­­¬­¬¬¬¬¬­¬­­¬¬¬­­®®®¿®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®¬­­­­­­­¬¬¬¬¬¬¬­¬¬¬­¬¬«««¬¬¬¬¬¬¬¬««««««««««««««««««««««««¬¬¬­¬­­¬­¬¬­¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬­­­®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬­­¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­­­¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬«««««««««««««««««««««¬¬¬¬¬¬­¬­¬­­¬­¬¬­¬­­¬¬¬¬¬­¬¬­¬­¬­®®¿1¿1¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬­­­¬¬¬¬­¬¬¬¬­¬¬«¬¬­¬¬¬­¬­¬¬¬¬¬¬¬«««««««««««««««««««¬¬¬­¬­­¬¬¬¬¬­­¬¬¬¬¬¬­­¬¬¬¬¬­­¬¬­­®®®®®¿¿1¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­­­­¬¬¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬«¬¬¬¬­¬¬¬¬¬¬««««««««««««««««««««««««¬¬¬¬­­­¬­¬­¬¬­¬­¬­¬¬­­­¬¬¬¬¬­¬¬¬­®®®®¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®­­­¬¬­¬¬­¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««­««««««««««««««««¬«««««««¬¬­¬¬­¬­¬¬®¬¬­¬¬¬¬¬­¬¬¬¬­¬­¬¬¬¬¬¬®®®¿¿¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬¬¬¬¬¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­­­­¬­¬¬¬¬¬­¬¬¬¬­­¬¬¬¬¬¬««¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««¬¬¬­¬¬¬¬­¬­­¬¬¬¬­¬­¬¬¬­­¬¬¬¬¬­¬­¬¬­¬­®®¿11®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬¬¬¬­¬¬¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­¬¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬¬¬««««¬¬¬¬¬¬¬¬¬¬««««««««««««««««¬­¬¬¬­¬¬¬­¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬­®¿®¿¿®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬­¬¬­¬¬¬¬­¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««¬¬¬¬¬¬¬«««««««««««««««««««««««¬¬¬«¬¬¬­¬­­­­¬¬¬­¬¬¬¬¬­¬¬¬¬­­®¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬¬¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­­¬¬¬­­­¬¬­¬¬­¬¬­¬¬¬­¬­¬¬¬¬­««¬¬¬¬«¬«««««««««««««««««««««««¬¬­­¬­®¬¬¬¬­­¬¬¬¬¬­­¬¬­­¬¬®®®¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­¬¬¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­¬¬­¬¬­­­¬¬¬­­¬¬¬¬­¬­¬¬««¬¬¬¬¬««¬«««««««««««««««¬««««¬¬¬­­¬®®®¬¬¬¬¬¬¬¬¬¬­­­¬¬­¬­¬¬¬¬¬¬­®®®¿¿¿1¿®1®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬­¬¬­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬¬¬¬­¬­­¬¬­­­¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬«¬¬«¬¬¬¬«««¬¬«¬«¬¬¬¬­¬¬­­®®®­­¬­¬¬­¬­­¬­¬¬¬­­­¬­­­¬­­®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­¬­¬¬­¬¬¬¬­¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­¬¬¬­¬¬¬­¬¬¬¬¬­­¬­¬¬¬¬¬««««¬«¬«¬¬¬¬«¬¬¬¬¬¬¬¬¬¬­®­¬­¬¬¬¬¬¬­¬¬­¬¬¬¬­¬­­­¬­®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬­­¬­¬¬­¬¬­¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­¬­­¬­­­­¬­­¬¬¬¬­¬¬­¬¬¬­¬¬«¬«¬«¬¬«¬«¬¬¬¬¬¬«¬«¬¬¬¬¬¬­¬¬­­­­¬­¬¬¬¬­¬¬¬¬¬­¬¬­­­­®®®®®®®¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬­¬¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­­¬¬­¬­­­­­­¬­¬¬¬¬­¬¬­¬¬¬¬¬¬««¬¬¬¬«««¬««««¬«¬¬¬¬¬¬­­¬­¬¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬­¬¬­¬­­®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬­¬¬¬­¬­­¬¬¬¬¬­¬¬­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­­¬­­¬­­­¬¬­¬¬­¬¬¬­­¬­¬¬«««««««««««««¬¬¬¬«¬¬¬¬¬¬¬¬¬¬­­¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬­¬¬¬®®®®®®®®®®®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬­­¬­­¬¬¬¬¬¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬¬¬­®¬¬¬­­¬¬­¬¬¬¬­¬¬¬««««««««««¬¬¬¬¬¬¬¬­¬¬««­¬¬­¬­­¬¬­¬¬­­­¬¬¬­­¬¬­¬¬­­¬¬­¬¬®®®®®®®®®®®®¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬­¬­¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬­­­­­­­­¬­¬¬¬¬¬¬­¬¬­¬¬¬¬«¬«««««¬¬¬¬««¬«¬¬­­¬¬¬«¬­¬­¬¬¬¬­­¬¬¬¬­­¬¬¬¬­¬¬­¬¬­¬¬­®­®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬¬­¬¬­¬­­­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬­­­¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬¬¬«««¬¬¬¬««¬¬¬«¬¬¬¬­¬­¬­­­­¬¬¬¬¬¬­­¬­¬­¬­¬¬­®¬­¬®®®®®®®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬­¬­¬¬¬¬­­­¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­­®­­¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬««««««¬¬¬¬¬¬¬­­¬¬­¬¬¬¬¬¬­¬¬¬¬­­¬¬­­¬¬¬¬¬­­­®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬¬­­¬­¬­­¬¬¬¬­¬­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬¬¬¬­­®­­¬¬¬­¬¬¬¬¬­¬¬¬¬­¬«««¬­¬¬¬«¬¬«¬¬¬¬«¬¬¬«¬¬¬¬­¬­­¬¬¬¬¬­­¬­¬­¬¬®­­¬¬­®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­¬­¬¬­¬¬¬­­¬¬¬­­­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬®®¬­­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬«««¬¬¬¬¬¬««¬«¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬­¬¬¬¬¬­­¬¬­¬­¬­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬­¬¬¬¬¬­¬­¬¬¬­¬­¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­®­¬¬¬¬¬¬­­¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬«¬­¬¬­¬¬­¬¬¬¬­­¬¬¬¬¬¬¬¬­¬­¬¬¬¬­¬­­­­­¬­®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬­­¬¬¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬­­­¬­¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬«¬««¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­­¬­¬¬¬¬­¬¬¬¬­¬­¬¬­¬¬­­¬¬¬¬­¬®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­­­­¬¬¬¬­¬¬­¬¬¬¬­¬¬­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬­­­­­­­­­­¬¬¬¬­¬¬­­¬­¬¬­¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬«¬¬¬­­¬¬­­¬­¬¬­¬­­¬­­¬­¬¬¬¬¬¬¬¬­®­®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬­¬­­­¬¬¬­¬­¬­­¬¬¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬­­­­¬­­­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬««««¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬¬­­¬¬¬¬¬¬¬­¬¬¬­¬­¬¬­­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬­¬­¬¬­¬¬­¬¬¬¬¬­­­­­®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­­­­­­­­­­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬«¬««¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬­¬­­­­¬¬­¬¬¬¬­¬­¬¬­®¬¬­­­­®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬¬¬¬­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬­¬­¬®®­®­¬­¬¬­­­¬¬­­¬­¬­­¬­¬­­­¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬­­­¬¬¬¬¬­¬¬­­­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­­­­­­¬¬¬­¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬««¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬­­­¬¬­¬­¬¬¬¬¬¬¬­­¬­¬­­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­¬¬­¬­¬¬¬­¬¬¬­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­­­­¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬«¬«««¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬«¬¬¬¬¬¬¬­¬®­­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­­¬¬®­¬­­®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­­¬¬¬¬­¬¬¬­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­­¬­¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬«¬¬¬¬«¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬®®¬¬­¬¬®­¬¬­¬¬¬¬¬¬¬¬­¬­­­¬®®®®®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬­­®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­­¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬­¬®­­­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­­¬¬®­­®®®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®¬¬¬¬­¬¬­¬­¬­¬­­­¬¬­¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬««¬¬­¬¬­¬¬¬¬¬­­¬¬¬¬¬¬­¬¬­¬¬­®­­®­¬®­­¬¬­¬¬¬¬­­¬­¬­®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®¬¬¬­¬¬­­¬¬¬¬¬¬¬­¬¬­­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬««¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­­®®®­¬¬¬­¬¬¬¬­­¬¬­®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬­¬­¬­¬¬­­¬¬¬¬­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­­­¬¬­­­­­­­­­¬¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬­­­¬­®¬¬­¬¬¬­¬¬­­­­­­¬¬®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬­­¬­¬¬­¬­¬¬­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­®¬¬­¬¬¬¬¬¬¬­¬¬¬¬­¬­­­­®­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­¬¬¬¬¬¬­¬¬¬­¬­¬­¬¬­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­­­­¬­¬­­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬««¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬­­¬«­¬¬¬¬­­­¬­­¬­­¬¬¬­­­¬­¬¬­¬®®­¬¬¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­¬¬­­¬­¬­¬­­­­¬¬­¬­®®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬¬­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬«¬«¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬«¬¬¬¬¬¬­¬¬¬¬¬­¬­¬¬¬­­­­¬¬­¬¬®­¬¬¬¬­­¬®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬­¬­¬¬­¬­­­¬¬­­¬®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬«¬«¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­­­¬¬¬¬¬¬¬­­¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­­¬¬¬­­¬­­¬­­¬¬¬®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­®­­­®¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬«¬«¬¬¬¬¬¬­­¬¬¬¬¬¬¬­¬­¬¬¬­¬­­­­­­¬­¬­¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬­¬¬¬­­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­®¬¬­­­­­¬¬¬­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬®­¬¬­¬­¬¬¬¬¬­¬­­­¬¬­­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬¬­¬¬¬­­¬¬¬­¬­­¬­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬­­­¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­­­­­¬­­¬­­¬¬­¬­¬¬¬¬­­­¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­­­­¬­­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬«««««¬¬¬¬«¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬­­¬¬¬¬­¬¬¬­­¬¬¬¬¬®­­¬­¬­¬­¬­¬¬­¬­®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬­¬¬¬¬¬¬­­¬¬­­¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬­¬¬¬­¬¬­¬¬­¬¬­­¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬¬­­¬¬­­¬­®®®®®®­­®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬­¬¬¬­¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­¬­¬­¬¬¬¬¬¬­¬¬­¬­¬­¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬­­¬¬¬¬¬¬¬¬­¬¬®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­¬­­¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬¬®­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬­¬­¬­¬¬­¬¬­­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬­¬¬¬¬­­­¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬¬¬­­­­¬¬­¬®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬¬­¬­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®¬­¬­¬­¬¬­¬­­¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­­®¬­­­­­­®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬¬¬¬­¬­¬­¬¬­¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬­­¬­¬¬­­­­¬¬­­¬¬¬¬­¬¬­¬¬¬­¬­¬¬¬¬¬­¬­¬¬¬¬¬¬­¬­¬­¬¬¬¬¬¬¬­¬¬¬­¬­¬­¬¬¬¬¬¬¬¬¬­¬¬­­­­­¬¬­¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­­¬¬­¬­­¬¬­­­¬¬­¬­¬¬¬¬¬­­­¬¬¬¬­¬­­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬¬¬¬¬¬­­¬­¬¬¬¬¬¬­®®­®®®­®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®¬­­¬¬­¬­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­­­¬¬­¬¬¬¬¬¬¬­¬¬­­­­­¬­­­¬¬¬­¬­¬¬¬¬¬­¬¬¬¬­¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­­­¬­¬®®¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬®­®®®¬­¬­¬­¬¬­¬¬­¬¬¬­¬¬­¬¬¬¬­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®­¬­¬¬­¬¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬­¬­­¬¬¬¬­­¬¬­¬¬­¬¬¬¬¬¬­­¬¬¬¬­¬¬¬¬­¬¬­¬­¬¬­¬¬¬­­¬¬­¬¬­­¬¬¬¬¬­­¬¬­¬­¬®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬®®®®®®®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬¬¬­¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬­¬¬­­¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬­¬¬¬¬¬­¬¬¬­­¬­¬¬¬¬¬­­­­®®®®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬­¬¬­­¬­¬¬¬¬¬­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬­­­¬¬­¬­¬¬¬¬¬¬¬¬¬­­¬­¬­¬¬­¬­­­­¬¬¬¬­¬­¬®­­­­®®­®®®¬­®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬¬¬¬¬­¬¬¬¬­­¬¬¬¬­¬­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­­¬¬¬­­¬¬­¬¬¬­¬¬¬­­¬¬­¬­¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬­®­­­­®®®®¬®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬­®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­¬¬­¬¬­¬¬­¬­¬­¬­¬¬¬¬¬­¬¬¬­¬¬¬¬­¬¬¬¬­¬­¬¬­¬­¬¬­¬­­¬¬¬¬­¬­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬®­­­®®®®®®®®®®®®®®®®®®®11¿®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬¬¬­¬¬¬­¬­¬¬­¬­­¬®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬­­¬­­­­¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬­¬­­¬¬¬­¬¬­¬¬¬¬¬¬­¬¬­¬­¬­­¬¬¬­­¬¬¬¬¬¬­¬¬­¬¬­¬¬­­¬­­¬­­­­­¬¬¬®®®®®®®®®®®®®®®®®®®¿¿1®®®®®®®®®®®®®®®®®®­¬­­­¬¬¬¬¬¬¬­¬­¬¬¬¬®¬¬¬¬®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬¬­­¬¬­¬­¬¬­¬¬¬¬­¬¬¬­¬¬¬­­¬¬¬­¬­¬¬¬¬¬¬­¬¬¬¬­¬­¬¬¬­¬¬­­¬¬¬¬¬¬¬­­¬¬­¬¬¬¬­­¬­¬¬¬¬¬¬­¬¬¬¬­¬­¬­¬­­­¬®¬¬­­¬¬­®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬­¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­¬­¬¬¬¬¬¬¬­¬¬­­¬¬¬¬¬¬­¬­¬­­¬¬­¬¬¬¬­¬¬¬¬¬­¬­¬¬¬¬­­¬¬¬¬¬¬¬¬¬­¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬®¬­¬­¬¬¬¬®­®®®®®®®®®®®®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬®¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®¬¬¬¬¬­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬­¬­­¬­¬­¬¬¬¬¬¬­­¬­¬¬¬¬­¬­­¬¬¬¬¬¬¬¬­¬¬®­®®®®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬­¬¬­¬¬¬­¬¬¬­¬­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬­¬¬­¬­¬¬­¬­­¬­¬¬­­¬¬­­¬¬­¬¬¬­¬­¬¬¬­­¬­®­®®®¬®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®¬®­¬¬¬¬¬­­¬¬¬¬¬¬­¬­¬¬­¬¬¬¬¬­¬¬­¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­¬¬¬­¬­­¬­¬¬­¬¬¬¬­¬¬­­¬­¬¬¬­­¬¬­­¬¬¬­­­¬­¬¬¬¬¬¬­¬¬¬¬¬®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­¬¬¬¬­¬¬­¬¬­¬¬­¬­­¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬­¬¬¬­¬¬¬¬­¬¬¬¬­¬­¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬­­­¬­¬¬­¬­­®®­­®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­­¬¬¬­¬¬­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬­¬¬­¬¬¬­­­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬­­¬¬­¬¬­­¬­¬¬¬¬¬¬¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬­¬­­¬­¬¬­­­­®®­­¬¬®®­®®®®®®®®®®®®®®¿¿®®®®®®®®®­¬­¬¬¬­¬¬¬¬¬­¬¬­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­®­­¬­¬¬¬¬­­¬¬­­¬¬¬¬­¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬­¬­¬¬­¬­¬¬¬¬¬¬¬­¬­¬¬­¬­¬¬¬¬¬­­¬¬­­¬­­¬¬¬¬­­¬¬¬¬­¬¬¬¬­¬­¬®®­­®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬¬­¬­®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®¬­¬¬¬¬­­­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬­­¬¬¬­­¬¬­¬¬¬¬¬¬­­¬¬­¬­¬¬¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬­¬¬¬­­­­¬¬­¬¬¬¬¬­¬¬¬¬¬¬®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬­¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬­¬¬¬¬­¬¬­¬¬­­¬­¬¬¬¬­­¬¬­¬¬¬¬­­¬¬­¬­¬¬­­¬­¬¬¬¬­­­¬¬¬¬¬¬¬¬¬­¬¬­­­­­­¬®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬®¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬­­­­­¬¬¬­­¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬­¬¬¬­­¬­­¬¬­­­­­­®­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬®®­®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®­­¬­¬¬­­­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬­¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬­­­¬¬¬­¬¬­­¬¬­¬¬­¬¬¬¬­­¬­¬­­¬­­¬¬­¬¬¬¬¬¬®­¬®­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬®­®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬®®®¬¬¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬­¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­­¬¬­¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬­¬¬­¬­­¬¬¬¬¬­­¬¬­¬¬¬¬¬­¬­¬¬­¬­­­¬­­­¬®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­¬­¬¬¬­¬¬¬¬­­­¬¬¬¬¬­¬¬¬­¬­¬¬­¬­¬­¬¬¬¬­¬­¬¬¬¬­­¬¬­¬¬­¬¬¬­¬¬¬¬­¬­¬¬­¬­¬¬¬¬¬¬¬¬¬­­¬­¬­¬­¬¬¬­­­¬®­¬­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬¬¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬­­¬¬¬¬­¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­­¬¬­¬¬¬¬¬¬¬­¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬­¬¬­¬¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­­­­¬­­¬¬­­¬¬­¬­¬¬­­¬¬¬¬­¬­­¬¬­­­®­¬­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬­¬¬­¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­¬¬­­­¬­¬¬¬¬¬­¬¬­¬¬­¬¬¬­¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬¬­¬¬¬¬­­¬¬­­­¬®­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­­¬¬¬¬¬¬­¬­¬­¬­¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬®®®®®®­¬¬¬¬¬¬­¬¬­­¬­¬­¬¬¬¬¬­¬¬¬¬¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬­¬­¬­­¬¬­¬­¬¬­­¬¬¬¬­­¬¬­¬¬¬¬­¬­¬­¬¬­¬­­­­¬®¬­­­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬­¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬­¬­¬¬¬¬¬¬¬¬¬­¬¬­­¬¬¬¬­¬¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬­­¬­¬¬­¬¬­¬­¬¬¬¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬­¬¬¬­¬­­­­­¬­¬­­­¬¬¬®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®­­¬­­¬¬­¬¬¬¬¬¬¬­­¬¬­­¬¬¬¬¬­¬¬­¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬­­¬¬¬¬¬¬¬¬­¬­¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬®¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬­­­­¬­­¬­¬¬¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬¬­¬­­­­¬¬¬­­¬­­­­­­®®®®®®®®®®®®®®®®¿®®®®®®®®®­­­¬¬­¬¬¬¬¬­¬­¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬­¬¬¬¬¬®®®®®®11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­­­­¬¬­­¬­¬¬­­­¬¬¬¬­­¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬­­¬¬¬¬¬­®¬¬®­­­­­¬­­­­­­¬¬­­­­­­®®®®®®®®®1®¿®®®®®®®®®®®®®®®­¬¬­¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬­¬¬­¬¬­­¬¬­¬¬­¬­®®®®®®®®®®1111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬­¬­­­¬­­­­­®­­­­¬¬­¬¬­­¬¬­­¬¬­¬¬¬¬­¬¬¬­¬¬­­­¬¬¬¬­¬­¬­­­­­­­­­¬­­­¬­¬­­­­®®®®®®®®®1®1®®®®®®®®®®®®®®¬¬¬¬­­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬­¬®®®®®®1¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬¬¬­­­­­­­­­­­¬¬¬¬­¬­­­¬­¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬¬­­¬¬¬­­­­¬­­­­¬­­­¬­­­®®®®®®®1¿¿®®®®®®®®®®®®®®®®®®¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬­¬¬¬¬­¬­­®®®®®®®11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­¬¬­¬¬­­­­­­­­­­­¬­¬­­¬­¬­­­¬¬¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬­¬­¬­­¬­¬­®®­­­­­­®­­¬­­­­­¬­¬¬¬¬¬®®®®®®®®¿1¿¿®®®®®®®®®®®®®®®®®¬­­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬­¬­¬­¬¬­®®®®®1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬¬­­­­­­¬­­­­­­­¬­­­¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬¬­¬¬­­­¬­¬¬¬®­­¬­­®­­¬¬­¬¬­­®®®®®¿®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬­­¬¬¬­¬­¬®®®®®®®®11¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­¬­¬¬­­­­¬¬¬¬­­­¬¬¬¬­­¬¬¬¬­¬­¬¬­¬¬¬­¬­¬¬­­­­­­¬®­­¬­­­­¬¬­­­®®®®®¿1¿®®®®®®®®®®®®¬¬¬­¬­¬¬¬¬­¬¬­¬­¬¬¬¬¬¬¬­¬­®®®®1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­­­­­¬­¬¬¬­¬¬¬¬¬­¬¬¬­­¬¬­­¬­¬­¬¬­¬­­­¬¬­¬¬­­®¬¬­­­¬¬¬¬­®®®®®®®®¿¿®®®®®®®®®®®®­¬¬­¬¬¬¬­­­¬­¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬®®®®1¿¿1¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬­­¬¬®­¬­­¬¬­¬­®­¬¬­­¬¬¬¬¬¬­¬¬¬­¬­¬­­­­¬­¬­­­­­­®®®­¬­­¬­­­­®®®®®®®®®®¿®®®®®®®®®®®®®®®®®¬¬­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬®®®®®®111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬­¬¬¬¬­­¬¬­®­¬¬­¬­­¬¬¬¬¬¬­­¬¬¬­¬¬¬¬¬¬­­¬¬­¬¬­®­­­®­¬­¬­­¬­­¬­­­­®­®®®®¿¿1¿®®®®®®®®®®®®®®®®®¬¬¬­¬­¬¬¬­­¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬®®®®®®®®11111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬­­¬­­¬¬¬­®­¬­¬¬¬­¬¬¬­¬¬¬¬¬¬¬­¬­¬¬­­­®¬­­®­­¬¬­¬­­­¬¬¬­­®®®®®1¿¿1¿¿®®®®®®®®®®®®®®¬­­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­®®®®®1111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­¬­®®®¬¬­¬­¬­¬¬¬­­¬¬­¬­¬¬¬­¬¬­¬­­¬¬­­­®­®®®­­®­­­­­¬¬¬¬¬­¬¬¬¬¬­®®®®¿11111®®®®®®®®®®®®®®®­¬­­¬­¬¬¬¬­¬¬¬­­­¬¬¬¬¬¬­­¬¬¬¬¬­¬¬®®®®®®®¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­¬­­¬­¬­¬¬­¬­¬¬­¬¬¬­­¬¬­¬¬¬¬¬­¬¬¬¬­­­­¬­­¬­­­­¬¬¬¬­­­¬¬­­¬¬¬­­¬¬­­®®®®®®®®11¿¿®®®®®®®®®®­¬¬­¬­¬¬¬¬¬­¬®¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬®®®®11¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­­­­­¬­®®®­¬­¬¬­¬¬¬­¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬¬­­­¬­¬¬­®¬­¬­¬¬­­¬¬¬¬¬¬¬­­¬®®®¿1¿¿®®®®®®®®®®®®®­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬®®1111¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­®®­­­­®¬¬®¬¬¬­¬¬­¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬­¬­¬¬­¬¬­­­­®­¬­­­­¬¬­­¬¬¬¬¬­­­­®®®®®®¿¿¿¿®®®®®®®®®®®®¬¬¬­­¬­¬¬¬­¬¬­­¬­¬¬¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬­¬®®®1¿11¿1¿¿1¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­­®­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬­¬­®®­­®®­­¬­¬¬­¬¬¬®¬¬¬¬¬¬®®®®®¿¿11¿¿¿®®®®®®®®®®®®®®­­­¬¬­­­¬¬¬¬¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬®®11111¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬®­­¬­­¬­¬­¬­­­¬­¬¬¬­­¬¬¬¬¬­¬­¬¬­¬¬¬¬­­¬­®®¬­®¬­­­¬¬­¬­¬¬­®¬­¬­­­®®®®®®®®®®¿¿¿¿¿11®®®®®®®®®®®®®®®®®®®­¬¬­¬­¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬­­¬®®111¿1¿¿¿1¿¿¿¿¿¿¿1¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­¬­­­¬­­­¬­­¬¬­­­¬­¬­¬¬­­®®®®®®®®®®®®®®­­¬¬¬¬­­¬­­®®®®®®®®®®®®®®®®¿¿¿11¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­¬¬¬­­¬­¬¬¬¬­¬­¬¬­¬­¬­¬¬­­¬¬¬¬­¬­¬¬®1¿1111¿1¿1111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬®¬­¬­­¬®­¬­­­­­­­­­¬¬­¬­¬¬­¬¬¬­­®­®®®®®®®®®®®®®®®®®®­­­­­¬¬¬­­­¬­­®®®®®®®®®®®®®®®®®®®1¿1¿¿1¿1¿1¿®®®®®®®®®®®®®®®®®­¬¬¬­­¬¬¬¬­¬­¬¬­¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬­­¬¬¬111¿111¿1¿¿¿1¿1111¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­¬¬¬­­­­¬­¬¬¬¬¬¬¬­®®®®®®®®®®®®®®¬­­­­¬¬¬¬­¬­­¬­®®®®®®®®®®®®®®®®®®¿1¿¿¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬­¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬®­11¿1111¿11¿¿1¿¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬­­¬¬­¬­¬­­­¬­®®®®®®®®®®®®®®®®®®¬®­¬¬¬­¬¬¬¬­¬­­­­®®®®®®®®®®®®®®1¿¿¿1¿¿¿11¿11111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬­¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­­¬®111111¿¿111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬¬­¬¬­¬¬­­¬­®®®®®®®®®®®®®®®®®®®®­¬¬­¬­¬­­®­­­­®®®®®®®®®®®®¿¿¿¿111¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­¬¬­¬¬¬¬¬­¬­¬­¬¬­¬¬¬¬­­¬­¬­¬¬­¬­¬­¬¬¬­­­®¿1111¿1¿¿¿¿1¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­¬¬¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­®®®®®®®®®®®®®®¿11111111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬¬­¬¬¬¬¬­­¬­¬­­¬¬­¬¬¬¬­¬¬­­­­¬­®¿111¿¿1¿11¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®¬¬¬­­¬¬­­®®®®®®®®®®®®®®®®®®®®®®®­­­­®®®®®®®®®®®®®111¿111111111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­¬­¬¬­¬­¬¬­¬¬¬¬¬¬­­¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬®¿111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬¬¬­¬­­®­­®®®®®®®®®®®®®®®®®®®®®®®®®­­¬®®­®®®­®®®®®®®®¿1111¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬­®®1¿1¿1¿¿¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬­­¬­¬­¬¬¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®­®®®®®®®11¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬¬­¬¬¬­­¬­­­®®®®®¿¿1¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­¬­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®­®®®®®®®®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬­¬­­¬¬¬­¬¬­¬¬¬¬­¬¬­¬¬­­­¬­­®®®¿1¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®¬­­­­­­¬­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬­®¿1¿¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬¬¬¬­­¬­¬¬¬¬­­¬¬­¬¬­¬¬­¬¬­¬¬­­­®®®1¿¿1¿11¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬­­¬­¬­®®®­¿1¿¿1¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬¬­¬­¬­­¬¬­¬­­­­¬¬®®¿1¿¿1¿¿¿¿11¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬­¬¬­®®®¿¿¿1¿¿1111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬¬­¬­­¬¬¬¬­¬¬¬¬¬­¬¬¬­¬¬®®®¿¿®¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬­­¬¬¬¬¬­¬­¬­¬¬¬­­¬­¿¿¿1¿¿¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­®®­¬¬­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­­¬¬­¬¬¬­¬¬¬¬¬­­¿¿¿¿®¿¿1¿¿11¿¿¿¿¿¿1¿¿¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­­­¬¬¬­­­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬­¬¬¬­¿¿1¿¿®¿1¿¿¿¿¿¿¿¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿1¿11¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬­¬¬¬¬1¿¿¿¿1111¿¿¿¿¿¿¿¿¿¿1¿¿¿¿11111111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿1¿1¿¿1¿11¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®­¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬«¬¬­¬¬¬¬­­¬¬¬­¬¬¬­¬1¿¿¿¿1¿1¿¿111111¿¿1¿11111¿¿¿¿¿¿¿¿¿¿1111111111¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿1¿¿¿¿¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿¿¿¿1¿11¿111®®®®®®®®®®®®­®®®®®®®®®®®®®¬¬®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­­¬¬¬¬¬­¬¬¬««¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¿¿1¿¿¿¿¿11¿1111111111111111111¿11¿1¿¿1¿¿1¿¿11111111111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿1¿¿1¿¿1¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®¿1¿¿¿¿1¿1¿11®®®®®®®®®­­®®®®®®®®®®®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬­¬­««««¬¬¬¬¬¬¬¬¬¬¬¬¿¿1¿¿¿¿¿1¿¿11¿¿11111111¿¿¿1111111111¿11¿¿¿¿¿¿11111111111¿¿¿1¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿¿1¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®¿11¿¿¿1®®®®®®®®­­­­­­¬­­®®®®®­®®®­¬¬­®®®®®®®®®®®®®®®®®®­¬¬¬««««¬«««««¬¬¬¬¬­¬­¬¿¿¿¿¿1¿1¿¿11¿¿111¿¿¿11111¿1¿¿¿¿¿111111111111¿¿¿11¿1111111111¿1¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®111¿1¿1®®®®­­¬¬¬­­¬¬­®®®®®®®­®®®®®­®¬®®®®®®®®®®®®®®®®®®®®®®®®®­¬­®®¬¬­¬««««««¬«««««««««««««««««¬¬¬­¬¬¬¬¬¿¿¿1¿¿11¿¿¿111¿¿1¿¿1¿¿¿11¿1¿11¿¿¿¿¿1¿111111¿1¿1¿¿11111111111111¿¿¿¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿111¿®­­­­­­­­¬®®®®­®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬««««««««¬««««««««««««««««««««¬¬¬­¬¬­­¿¿¿¿¿¿¿¿¿111¿¿¿11¿¿¿11¿¿111¿¿¿¿¿¿¿¿¿¿1¿¿1111¿¿111111111111¿¿1¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­­¬¬­¬®®®®­®®®¬®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®­­¬¬­¬««««««««««««««««««««««««««¬¬¬­¬11¿1¿¿1111¿¿¿1¿¿¿11111111111111¿1111111111111¿¿1¿11¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬¬­­­­­¬­­­¬­­­®­­­­¬­®®®®®®®­¬¬­­¬¬¬¬¬««««««««««««««««««««««¬¬¬¬¿111¿111111¿¿¿1¿¿¿1¿1111111111111111111111111¿11¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­­­­­­¬¬¬­¬­­¬¬¬¬­¬¬­¬­­­­­­¬­®­­­­­¬­¬­¬­®­®®®®®®®®®®¬­­¬¬­¬¬­¬¬¬¬«««««««««¬«««««««««««¬««¬¬¬¬11¿¿1¿¿111¿111¿¿¿1¿11111111111111111111111111¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®¿®®®®®®®®®®®®®¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬¬­¬¬­¬¬­¬­­­­­­­­¬¬¬¬¬­¬¬­­¬¬¬¬¬­¬®®®®®®®®®®®®®®®­­¬¬­¬¬­¬¬««««««««««««««««««««««««««««¬¬¬¬¿11111¿¿¿¿111¿1111111111111¿¿¿¿1111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­®®®®®®®®®®®®®®®®®®­®®®®®®®¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­¬¬¬¬­¬¬¬­¬¬¬¬­¬­­¬¬­¬­¬¬­­¬¬¬­¬¬¬¬­¬¬¬¬¬¬®®­®®®®®®®®®®®¬­­­­¬¬¬¬¬««««««««««««««««««««««¬¬¬­¬¬¬111¿¿¿¿¿¿¿¿¿11111111¿¿¿¿¿¿111®®®11¿®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬¬­¬¬­¬¬­­¬¬¬¬¬­­¬¬¬¬¬­¬­­¬­¬¬¬¬¬¬­¬­¬­­®®®®®®®®®®®®®®®¬­­­­¬­¬¬­¬¬««««««««««««««««««««««««¬¬­­¬¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿1®®®®­­®®®®®®®­­®®®®®®®®®­­­­­¬¬¬¬¬¬­­¬¬­­¬­­¬­¬­¬¬­­­¬¬­­¬­­­¬¬¬­­¬­­¬­¬­¬¬­­®®®®®­­®®®®®®®®®®®¬­¬­­­¬¬¬¬­­¬­­¬¬­®®¬¬­¬¬­««¬«««¬««««««««««««¬¬¬­¬¬¬¬­¬­¬­­­­­¬¬¬¬­¬­¬¬¬­¬««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­®®®­®®­­­¬¬­­¬¬­¬¬¬­­­­­­¬­¬¬¬¬¬­¬¬­­¬­­­¬­¬­¬¬­¬¬­­¬­¬¬­­¬­­­­­­®®­®®®®®®®®®®­­­¬­¬­­¬­¬¬­¬­­­­­­­¬­®®®¬¬¬««««««««««««««««««««¬­­¬­­¬­­­®­¬¬­¬¬¬­­¬«««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬­¬¬¬­­­­­­¬­¬¬­¬­¬¬­¬­­¬¬­¬¬¬­­¬­¬¬­­¬¬­­­­®®­®®®®®®®®®­­¬­¬¬­¬¬­¬­­¬­¬¬¬¬­­­­­¬­¬¬­®­­®®®¬­®¬¬¬¬¬«««««««««««««««««««««««««­¬­­­­¬¬¬¬­¬¬¬¬­­­¬­¬¬¬­«¬«««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬­®­­®­­­­¬­¬¬­¬­­­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬­¬­¬¬¬¬­­¬¬¬­­¬­­­­¬¬¬¬¬­­¬­­­­­¬¬®®®®®®®®®®®®®­¬­­­­­¬­¬¬­¬­­¬­¬­­¬¬­­­­­­­¬¬­¬¬­¬«««««««««««««««««««««««¬­¬¬¬¬­­¬­¬¬¬­®­­¬­¬­­¬««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®­­¬¬­¬¬­­¬¬¬¬­­¬¬¬­¬­¬¬¬¬¬­­¬¬¬¬¬¬­­¬­¬­­¬¬­¬¬¬­­­­¬¬¬®®®®®®®®®®®®®®®­­­­­­­¬¬­¬¬­¬­¬¬­¬¬­­¬¬­­¬¬¬­­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««¬­¬¬¬­¬¬­¬­­¬®­¬­¬¬­­««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­­­®¬­¬­¬¬­¬¬­¬¬¬­­­¬¬­¬¬¬¬¬¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬­¬­­¬¬¬­¬¬¬¬­¬­­¬¬¬­®®­®®®®®­¬­­­­­­¬¬­¬¬­­­¬­¬­¬­­­­¬¬­¬­¬¬¬¬­¬¬¬««««««««««««««««««««««¬¬¬¬¬­­¬­¬­¬­­¬¬®¬­­¬«««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­­­®­­­­­­­­­­­­­­­®­¬¬¬¬­­­­¬¬­¬¬­¬¬­¬­­¬¬­­¬¬­¬­¬¬¬­¬¬­¬¬¬­­­­­­¬­¬¬­¬¬¬¬­¬¬­­¬­¬­¬¬®­­­­®®­®¬¬­­­­¬­­¬¬¬¬­­­¬­­­¬­¬­­¬¬­­­­­¬­¬¬­¬««««««««««««««¬¬¬¬¬¬­¬­­¬®¬¬¬¬¬­­¬¬­«¬«««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­¬­­®­­­­­­­­­­¬¬­¬¬­¬¬­­¬­¬­­¬­¬¬¬¬­­¬¬¬¬¬¬­­¬¬¬­¬¬¬­­¬­­¬­¬¬­¬­¬¬­­­­¬¬­­­­­­®­¬­­¬¬¬­­­­¬­¬¬­¬­¬¬­­­¬­¬­¬¬­¬­­­¬¬­­®®­­¬«««««««««««««««««««¬¬¬¬¬¬¬¬­­¬­­­®¬­­¬­­¬¬¬¬­¬¬«««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬­­­­­­­­­­­­­­­­­­­¬­¬¬­¬­­­¬­¬¬¬¬¬¬­­¬¬­¬¬¬¬¬­­¬¬¬­­­­¬­­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬­­­­®®­¬­­¬¬¬­­¬­¬­­¬¬¬¬¬¬­­­¬­¬¬­­­¬­­¬­¬®­¬­«««««««««««««««««««««­¬¬¬¬¬­­¬¬¬­¬®®¬¬¬¬¬¬­­¬­¬«¬¬««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­­­­¬­­­­­­­­­­­­¬­­¬­¬­­­­­®­­¬¬­¬­¬¬­¬¬¬­¬¬­¬­­¬¬¬¬­¬¬¬­¬¬­¬­¬¬­¬¬­¬¬¬­¬­­­¬¬¬­­­­¬¬¬¬­¬­­­­®­­­¬¬¬¬¬¬­¬­­­®¬­¬­¬¬­¬¬¬¬¬¬­¬­¬¬­­¬­¬¬¬­­­¬­­­««««««««««««««««««««««««¬¬¬¬¬­­¬¬­­¬¬®­¬­¬¬­­¬­«¬«¬«««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬­¬­­­­¬­­­­­­­­¬­­­­®®®­­­¬­¬­¬­­­¬¬­¬¬¬¬­­¬¬­¬¬­¬¬­¬¬¬¬¬­¬¬­­¬¬­¬¬­¬­¬¬¬­¬­¬¬¬¬¬¬­¬¬­¬­­­­­­­­®®­­­­¬¬­¬­­­¬­¬¬¬¬¬¬¬­¬¬­­­¬¬¬¬¬­¬¬­­¬­¬¬­­¬¬¬¬««««««««««««««««««¬­¬¬¬¬¬¬­¬¬­¬¬­¬­®¬­¬­¬¬¬¬«««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®­­­­­¬­­­­¬¬­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬­­­­­¬¬¬¬¬­­­­­¬­¬­¬­¬¬¬­¬¬­¬¬­­¬¬¬¬¬¬­¬­¬¬¬¬¬¬­¬¬­­­­­­­®®­­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­¬­­­­¬­¬¬¬¬­¬¬­­¬­­­­­««««««««««««««««­¬¬¬­­¬¬­­¬­¬¬­®¬¬¬¬­­¬¬¬¬¬«««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­­­­­­­­­­­­­¬¬­­­­­¬­­¬­¬¬­¬¬¬¬¬­¬¬­­­¬¬­¬¬¬¬¬­¬¬¬¬­¬¬¬­­¬­¬­­¬¬­¬¬¬­¬¬­¬­­­­­­­®®­­­­¬­¬­¬¬¬¬­¬­¬¬­¬­­¬­­­­¬¬­­¬­¬¬¬­¬­¬­­­­«««««««««««««««««««««¬­¬­¬¬¬­¬¬­¬¬­¬¬¬­­¬¬«««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­­­­­¬­­¬¬¬¬­­­­­¬­­­­­­¬¬­¬¬­¬¬­¬¬­­­­­¬­¬¬­­¬­¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬­¬¬¬¬¬­¬­¬­­­­­­­®­­­¬­­­¬¬¬¬¬¬¬­¬­¬¬¬¬­¬­­¬­¬¬­¬¬­¬¬­­­¬­­­­­¬­«««««««««««««««««««««¬­­¬¬¬­­¬­­­­¬¬¬­¬¬««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬­­¬¬¬¬­­­¬¬¬¬¬­­¬¬­­­®­¬­­¬¬­¬¬¬¬¬¬¬¬­­¬¬¬¬­¬¬¬­¬¬¬­¬­­¬¬¬¬¬­¬­¬­¬¬¬­¬¬­¬¬­¬¬¬¬­¬­­­­­­­®®®¬¬¬­¬¬¬¬¬¬­¬¬­¬­¬­¬¬­­¬¬­¬¬¬¬­¬¬¬­¬­¬­¬¬­­¬­««««««««««««««««««««¬¬¬¬­¬¬­¬¬­­®¬­­¬¬­­¬¬­¬««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­­­­­­¬­¬­­¬¬¬­­­­­¬­®¬®¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬­­¬¬¬­­­¬­¬¬­¬¬­¬­¬­­­­¬­¬¬¬¬­­­­­­­­­­­­­¬¬­­¬¬¬¬­­¬¬¬¬­­¬¬­­¬­¬¬­¬­¬¬­¬¬­­­­­­­­«««««««««««««««««««««««¬­¬­¬­¬­­¬­­®¬­®®¬¬­®­­¬¬««««««««««««««««®®®®®­­®®­­­­­­­­­­­­­­¬¬­­­¬­¬­­­¬­¬¬¬­¬¬¬¬¬¬­­¬­­­­­¬­¬¬­¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬­¬­¬­­®®¬­­¬¬­¬¬­¬¬¬¬¬¬¬¬««««­««««««««««««««««««««¬««««««««««««««««¬­¬®®®­¬¬­¬¬­­¬¬«««««««««««««««««®®®®®®®®®­®®®¬­­¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬­¬¬­¬­¬¬¬­¬­¬­¬¬¬¬­¬­¬­­­¬®®¬¬­­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬«««««««¬««¬«««««««««««««««««««««««««««««««¬¬®¬­¬­«««««««««««««««««««««®®®®®®­­­­­­®®®­­­­­­­¬¬¬¬­¬¬­¬­¬¬¬¬­¬¬­­­­­­¬¬­­­­¬­¬¬­¬­¬¬­¬­­¬¬­¬¬¬¬­­­­¬­­­¬­¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬««¬««¬¬««««««««««««««««««««««««««««¬¬­¬¬¬¬¬¬¬¬­¬­¬¬¬­¬«««««««««««««««®®®®®®®®®®­­­­¬¬­¬­¬¬­¬¬¬¬­­¬¬¬­¬­¬¬¬­­¬¬¬­¬­¬¬­¬¬­­¬­¬¬­­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­­­¬¬­¬­¬¬¬­®­¬¬­­­­¬¬¬¬¬¬¬­««¬¬«««««««««««««««««««««««««««««««««««¬¬¬¬­­­­­¬¬¬­­¬«««««««««««««««««««««®®®®®®®®®­­­­®­®®­¬­¬¬¬­­¬­­¬¬­¬­¬­¬­¬¬­¬­¬¬­¬¬­¬¬­­¬¬­¬¬­­­¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬­­¬­¬¬­­¬¬­­¬­­­­¬¬¬­¬¬¬¬¬¬¬¬¬««¬¬¬«««««««««««««««««««««««««««««««««­­¬®­¬­¬¬¬­«¬«««««««««««««««®®®®®®­­®®®­®®®®­­­¬¬¬­­¬¬¬¬­¬­¬¬­¬¬¬­­­­¬­¬¬¬­¬­­¬¬­¬­­­¬­¬­¬¬¬­­¬¬¬­­¬¬­­­­­­¬¬¬­­­¬¬¬¬¬««¬¬¬««««««««««««««««««««««««««««««««««­­®¬¬­¬­­¬««««««««««««®®®®®®®®­­­­­­®®®­­®­­¬¬¬¬­¬¬­­¬¬¬¬¬­¬­¬­¬­­¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬­­­¬¬¬¬¬¬¬¬­¬­­­­¬­­¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬«««««««««««««««««««««««««««««««««­«­­¬¬®¬¬­¬¬­­«««««««««««««««««««««®®®­­­­­­­®­­­­­­¬­¬­¬¬¬¬¬¬­¬¬­¬¬¬­­­­¬¬­¬­¬¬¬¬¬­­¬­¬¬­¬¬¬¬¬­¬­¬¬­¬­¬­¬­­­­­¬­¬¬¬­¬¬­­¬¬¬¬¬¬«««¬««¬¬­«««««««««««««««««««««¬­¬«««¬¬­¬¬¬¬¬®­¬­­¬««««««««««««««««««®®®®®®®®®®®­­­¬­®­­­­­¬¬­­­¬­­¬¬­¬¬¬­¬¬­¬¬¬­­¬¬¬¬¬¬­¬­­¬­¬¬¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬¬¬­¬­­­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬««­¬«««««««««««««««««««««««««¬¬¬­®¬¬¬¬¬­­¬¬­«¬««««««««««««««®®®®®®®®®­­­­­­­­¬­­­¬­­­¬¬­¬¬­¬¬­­¬¬¬­¬­­¬¬¬­­¬¬¬¬¬­­¬­­­¬­¬¬¬¬­­¬¬¬¬¬¬¬¬­¬¬¬­­¬¬­­¬¬¬¬¬¬¬­¬­¬¬¬«­¬«««««««««««««««««««««««««««««®­­­¬­­¬¬¬¬­¬¬««««««««««««««««««®®®­­­­­­­­­®®®®­­­­­­­­¬­­­­­­­¬¬­¬¬­¬¬­¬­¬¬­­­¬¬­¬¬­¬­­¬­¬¬­¬¬¬­¬¬­­¬­¬¬­¬¬¬­¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬««¬¬¬¬¬«««««««««««««««¬«««««««««««««««¬­¬­¬¬¬¬¬­­¬­¬«¬¬«««««««««««««««««®®®­­­­­­­­­­¬¬­¬¬¬¬¬­­¬­¬­¬¬¬¬­¬¬¬­¬­¬¬­¬¬­­¬­­­¬­¬­¬­¬¬¬­­¬¬¬¬¬¬­­¬¬¬¬¬­¬¬­­­¬¬¬¬«¬«¬¬¬««««««««««««««««««««««««««««««««¬­¬­¬¬­­¬­«¬«¬««««««««««««««««««®®®®®®®­­­­­­­­­­­®®­­­­­­­¬­­¬¬¬¬¬­­¬­­¬­¬­¬¬¬¬¬¬­¬­­­¬­­¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬­­­¬¬¬¬¬¬­¬­¬­­¬¬­¬­¬¬­«¬¬¬¬¬¬«¬««««««««««««««««««««««««««­«¬¬¬­®¬­¬­¬¬¬¬««««««««««««««««««««««®®®®®®®®®­­­­­­­­­­­­­­­­­­­¬­­­­­­­¬­­¬¬­¬¬­¬¬­¬¬¬¬­¬­¬¬­¬¬¬¬­¬­¬¬¬­¬¬­¬¬­¬¬­­¬¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬««¬¬«««¬««¬¬««¬«««««««««««««««««««««««¬«¬¬¬¬®¬¬¬¬­­¬¬¬¬¬«««««««««««««««®®®®®®®­­­­®®­­­¬¬­­­¬­¬¬­¬¬­­­¬­¬¬­¬­¬¬­¬­¬¬­¬¬¬¬­­¬­¬¬­¬­­­­­¬¬­¬¬­¬¬­­­¬­­¬¬­¬­¬¬¬­¬¬¬­­¬­¬¬¬¬­¬¬¬¬¬­¬¬««««¬««­««¬««««««««««««««««««««««««¬¬­¬­¬¬¬­­¬¬««««««««««««««««««®®®®®­­­­­­®­­®®®­­­­­­­­¬¬¬­¬­­­¬¬­¬­¬¬­¬¬­¬¬­¬¬¬­­­¬­­­¬¬¬­­­®®®­¬¬¬¬¬­¬¬­­¬­­¬­¬­¬¬¬¬¬¬­¬¬¬¬­¬­¬¬¬¬­¬¬¬¬¬««««««««««««««««««««««««««««««««««­­­¬¬¬­¬¬««««««««««««««««­®­­­­­­­­­®®®®®­­¬¬¬¬­¬¬¬­¬¬¬­¬¬¬¬­­¬¬¬­¬¬¬­­¬¬¬¬¬¬¬¬¬­­­­­­¬­­¬¬­¬¬­¬­¬¬¬­¬¬¬¬¬¬¬­¬¬««««««««««««««¬¬«««««««««««««««¬«««««««««««««¬­­­®­¬­­¬¬­­¬¬­¬«««««««««««««««««««®®®®®­­­­­­­­¬­­®¬­¬¬¬­¬­¬¬¬­¬¬¬¬­¬­¬¬­¬¬¬¬­¬­¬­¬­¬¬¬¬¬­¬¬­¬­¬­¬¬­¬¬­¬®®®¬¬¬¬¬¬¬¬¬¬¬¬¬«¬«««««««««««««¬««««««««««««««««««««««««««««¬«¬¬¬­¬­®¬­¬­¬­®®¬¬­®­­¬¬««««««««««««««««®­­­­­­­®­®®®­­¬¬­¬¬­­¬­¬­¬¬­¬­¬¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬­¬¬­­­­¬¬­­¬­¬¬¬¬¬¬¬­¬®¬¬¬¬¬¬¬¬¬¬¬«­¬¬«¬«««««««««««««««««¬«««««««««««««««««««¬¬­­­®­¬¬®¬¬­¬¬­¬««««««««««««««««««®®­­®­­­­­­®®®­®­¬­¬¬­¬¬­¬­¬­¬­¬­¬­¬¬­¬¬­¬­­¬­¬¬­¬¬¬¬¬¬­¬­¬­¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬«¬«««««««««««««««««««««¬«««««««««««««««««¬««««¬¬­¬­¬®®¬­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬«¬««««««««««««««««­­­­®­­­®­®®¬­¬­¬¬­¬­¬¬¬¬­¬¬­¬¬­¬¬¬­¬­¬¬¬¬­¬­¬¬­¬¬¬¬­¬­­¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬¬¬«¬¬­¬¬¬¬¬¬¬¬¬¬«««««¬««««««««««««««««««««««««««««¬««­¬­­¬¬®¬¬¬­­­¬¬¬­­¬«¬«««««««««««««®­®®­­­­­­­­®®®®­­¬­¬­­¬­¬¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬­­­¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬­­­­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««¬«««««««««««««¬­«««««¬¬®¬­¬¬®¬¬¬¬­­®¬­®®­¬¬­¬¬¬¬¬¬«««««««««««««««««®­­­­­­­®®®®¬¬­­¬­­¬¬­­¬¬¬­¬¬­¬­¬¬¬¬­¬­¬­¬¬¬¬¬­­¬¬­­¬¬¬¬¬¬­¬««««««««««««««««««««««««««««««««««­««««¬¬­¬­¬­®­¬¬¬¬¬®¬¬«««««««««««««««««««««­®­­­­­­®®®®®®®®®¬­¬¬­¬­¬¬¬­¬­¬¬¬¬­¬­¬¬­­­¬¬¬¬¬­¬¬¬­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬«­¬«««««««««««««««««««««««««««««««««««««¬««««¬¬¬¬­®®®¬¬­­­¬­¬­­¬¬¬¬«««««««««««««««««®®®®®®­­­­­­­­­®­¬¬­¬­­¬¬­¬­¬¬­­­¬­­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬­­¬¬¬¬¬­­¬¬¬¬­¬¬¬««««««««««««««««««««««««««««««««««««««««¬¬««¬¬­¬­®®¬­¬­­¬¬­¬­¬­¬¬¬­¬¬¬¬¬¬««««««««««««««®­®®®­­­­­­®®®®®­¬¬¬¬­­¬­­­­­¬­­¬¬¬¬­¬¬­¬­­¬¬­¬¬¬­¬¬¬¬¬¬­­¬¬¬­¬««¬««««««««««««««««««««««««««««««««««««««««¬¬¬­¬¬­¬­­¬­¬¬¬¬¬¬¬««««««««««««««««««««®­­®­­®­­­­®®®¬­¬¬­­­¬¬­¬¬¬¬­¬­­­¬¬¬­­­­¬¬¬¬­¬¬¬¬¬­¬¬­­­¬­¬¬¬¬­¬«¬¬¬¬­«««««««««««««««««««««««««««««««««««­«¬¬­¬­¬¬­­¬­¬¬­­­­­¬­¬¬¬¬«««««««««««««««®­­­­®­­­­­­­­­®­­¬­¬¬­¬¬­¬¬­­¬­­­¬­­¬­­­¬¬¬¬¬¬¬­¬­¬¬­¬­¬¬¬­¬¬¬¬¬¬­¬¬¬¬«««««««««««««««¬««««««««««««««««««¬«­­®®­¬¬­­­­¬¬­­¬­¬¬¬««««««««««««««««®­­­­­­­­­­­­®®®®®¬­­¬­¬­¬¬­­¬¬­¬­¬­¬­­¬­¬¬¬¬¬­¬¬¬¬­¬¬¬­­­¬¬­­¬¬¬¬¬­­­¬¬¬««««««««««««««««««««««««««««««««««««¬¬¬¬¬¬­¬¬¬¬­­¬­¬¬¬­¬¬¬­¬­¬¬¬¬«««««««««««««««««­­­­­­­­­­­­­­­­®®®­­¬¬¬¬¬¬­­¬­­­­¬­­¬¬­­¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­­¬¬¬¬¬¬¬¬¬­¬«¬¬««««««««««««««««««««««««««««««««««¬¬­­­¬¬¬¬­¬¬­¬¬¬­­¬¬­¬­¬¬­­¬«¬¬¬««¬«««««««««««««­­­­­­­­­­­®®­¬­¬¬­¬¬¬¬¬¬­¬­¬¬¬¬­­­¬­¬¬¬¬¬¬¬¬¬­­¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««­­¬¬¬­¬¬­¬­­­­¬­¬¬¬¬¬¬¬¬««««««««««««««««®®®®®­­®­­­­­­­­­®­­¬¬¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬­¬­¬­¬­­¬­­¬­¬¬¬¬­¬¬­¬¬­­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­­¬¬«¬¬­­­¬¬¬­­¬­¬¬¬¬­®­¬¬¬­¬¬««««««««««««««««««««®®®®®­­­­­¬¬¬­­¬¬¬­¬¬­¬¬­¬­­¬¬¬¬¬¬¬¬«¬¬¬««««¬«««««¬«««««««««««««««««««««««««««««««««««¬«««««««««««««««««¬¬¬¬¬¬¬­¬­­¬­¬®­­­¬¬¬¬­­­¬¬¬¬¬«««««««««««««««««««¬®®®®­­®®®®­­®¬­¬¬­­¬­¬¬­¬¬¬¬­­¬¬¬¬««¬«««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬«­­¬­­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬­««««««««««««««««®®®®®®®®®®¬­¬­¬­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬­¬­¬¬¬­¬¬®®­­¬¬¬¬¬¬«­¬¬««¬«««««««««««««®®®®­®®®®­­­¬¬¬­­¬¬¬­¬¬­¬­­¬¬¬¬¬¬¬¬­¬¬¬«««««­«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬­¬¬®¬¬¬­¬¬¬¬­¬«¬­¬¬­«­¬¬««««««««««««®®®®­®­®®­­®®­­­­¬¬­¬¬­¬¬¬¬­­­¬¬¬¬­¬­­­¬¬¬¬¬«­««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬¬¬¬¬­¬¬¬¬®¬¬¬¬­¬­¬¬«¬¬««««««««««««­®­®­­®®®®®­¬­¬­¬¬¬­¬­¬­¬¬­­¬­¬«««¬¬«««««««««««««««««««««««««««««¬««««««««««««««««««««««¬«««««««««««¬¬¬¬­¬­­¬¬®­¬¬¬­¬¬¬¬¬¬¬¬­«««¬«««««««««­««­®­®®®®®®­®­¬¬¬­¬¬­¬¬­­¬¬­¬­­¬¬¬¬««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­¬¬¬¬­¬®¬­¬¬¬­¬¬¬¬«««¬¬¬­«««««««««««««««««®®®®­®®®®­­¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬«««¬­«««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««¬«¬¬¬¬¬¬¬¬®­­¬­¬¬¬¬¬«««¬¬««««««««««««««««®®®®­®­­®®®­­­­­¬­­¬­¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««¬¬­¬¬¬¬¬¬­¬­¬«««­¬««««««««««««««««¬«®®®®®®®®®®®®®­­­­­­­­­­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬«¬«««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««¬«¬«¬¬¬«¬¬­¬­¬¬¬­¬¬«­¬«««««««««««««®®®­®®®®­­­­­­­¬¬­¬¬­¬¬­¬¬¬¬¬¬««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬«¬¬­¬­¬¬¬¬­­®­­¬¬¬¬¬¬¬­¬««««««««««««««««®®®®­­®®­­®­­­­®¬¬­¬­­¬¬¬¬­¬­¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬««««««­­¬¬¬¬¬¬­­¬¬­¬¬¬¬¬¬«¬««¬««««««««««««««««««®®®®®®®®­­®®®­®®®­­­­­­¬­¬¬­¬­­¬­¬­¬¬¬­¬¬­¬¬«««««««««««««««¬«««««««««««««««««««««««««««««««««««««««¬¬­¬­­­­¬­¬¬¬¬¬¬«««««««««««­«««««««­­®®®­®­­®®­®­®­­­­­­­­¬¬¬¬­¬¬¬­¬­­­¬­¬¬¬¬¬¬«««¬««««««««««««««««««««««««««««««««««««««««««««««««««««­­¬«¬¬¬­­®­­¬¬¬¬¬¬¬¬«««««««««««««««««««««««­®®­®®®®­¬­­­­­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬­¬¬­­¬¬¬««««««¬¬««««««««««««««««««««««««««¬«««««««««««««««««««««««­¬¬¬¬¬¬®¬¬¬¬¬¬¬««««¬««««««««««««««««««®®­®®®®®®®®®­­­­­­­­¬­¬¬­¬­­¬­¬¬­¬¬¬¬¬««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«¬¬¬­®®®¬­®¬¬¬«««««««¬««¬«««««««««««««««®®®­®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬­­­«««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««­­¬«­­®­¬¬¬¬¬¬¬«««¬«««¬«««««««««««¬««««««®­®®­®®®®®­®®®®®®®®®®®®®®®®®­­®®®­­­­­¬¬­¬¬­¬¬­¬¬­¬¬¬­¬¬¬«««­¬¬««¬«««««««««««««««««««««««««««««««««««««««««««««««­¬¬¬¬¬«¬­­®®¬­«««««¬««««««««¬«««¬¬««««««®®®­®®®®®®®®®®®®®®®®®®®®®¬­­¬¬­¬®­¬¬­¬¬¬¬«««¬¬«««¬«««««««««¬¬«««««««««««««««««««««««««««««««««««««««¬¬«¬¬¬¬®­¬«««««««««¬««««««««««««¬««««­®®­®®®®®®®®®®®®®®®®®®®®®­®®®­¬­¬­¬¬­¬¬¬¬­­¬¬¬¬«««¬¬««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««­¬­­­¬®®¬¬¬«««««««««¬¬«««««««««««¬«««¬®®®®­®®®®®®®®®®®®®®®®®®®®®®­®®®­­¬¬¬­­¬¬¬¬®­¬¬¬¬¬¬¬¬¬««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­¬¬¬­¬¬­¬®¬¬¬««««««¬«««««««««««««««««««¬®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®­­­­®®®®®­­­®­­­¬­­­­¬¬¬¬­¬¬¬¬¬««¬¬­¬¬«««««««««««¬«««««««««««««««««««««««««««««««««««««««««««««­¬¬¬¬­¬¬¬¬®­¬­««««««««¬«««««««««¬««««®­®®®®®®®®®®®®®®®®®­®­®®®®®­­¬­­­­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬«««¬¬¬««««««««««¬««««««««««««««««««««««««««««««««««««««««««««««««««¬««¬¬¬¬­«­­­¬¬«¬¬««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­¬®¬¬¬¬¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬­¬««¬¬¬««¬«««««««««««««­­¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««­¬¬¬¬¬­¬¬­¬®¬¬¬««««««««««««««««­­¬«­®®®®®®®®®®®®­®®®®®®®®®®®®­®®­­­­¬­®®¬­¬¬¬¬­¬¬¬¬¬¬«­¬¬¬«««««««««««««««¬««««««««««««««««««««««««««««««««««««««««¬¬¬­¬¬­¬¬­­­¬«¬««««««««««««««««¬¬­««««®®®®®®­®®®®®®®®®®®®®®®®®®®®®­®®­­¬®­®®¬¬­¬¬¬¬­¬­¬­¬¬¬¬¬¬«¬¬¬¬««««««««««««««««««««««««««««««««««««­««««««««««««««¬¬¬¬¬¬¬­­¬­¬¬¬­««««««««««««««««««««¬««®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬¬¬­¬¬¬¬«¬¬«««««««««¬«««««««««««««««««««««««««««««««««««««««««««­­­¬¬¬¬­­­¬¬¬¬¬¬««««««««««««««««««¬®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬¬¬­¬¬­¬¬¬«««­¬¬««¬¬«¬««««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««­¬¬­¬¬¬®¬¬«««««««¬¬¬««««««««««­««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®­­¬¬­­¬­¬¬¬¬¬¬«­¬¬­¬««¬««««««¬«¬«««««««««««««««««««««««««««««««««««««««««««¬­¬­¬¬¬¬¬¬¬¬¬¬®¬­«««««««««««¬«««««««««««««­«««®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬­¬¬­­¬­¬¬¬¬¬­¬¬¬«­¬««¬¬««««««««««««¬««««««««««««««««««««««««««««««««««««­­¬¬¬¬¬¬¬¬¬««««««««««««««««««««««®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­­¬¬­¬­¬¬¬¬­­®¬­¬¬¬¬«««««¬­¬¬¬««««««««««««¬¬«««««««««««««««««««««««««««««««««««««««««¬­¬­¬¬¬¬¬««««¬««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®­®®¬­­¬¬­­­­¬­­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬««««¬«««««««««««««««««««¬««««««««««««««««««««««««««««««««««««­¬¬­­¬¬­¬­®¬««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®­¬­­­­­¬¬¬­­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­««­«««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«¬­¬«®««««««««««««««««¬««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬­¬­¬­¬­­¬¬¬­¬­¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬««¬««««««¬««««««««««««««««««««««««««««««««««««««««­«¬­­¬««««««««««««««««««««««¬««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­¬¬­¬¬­¬¬­¬­­­¬¬­­¬­¬¬­¬¬¬¬«¬¬¬¬¬¬¬««¬«««¬«««««««««¬««««««««««««««««««««««««««««««««««««««««¬«¬¬¬««««««««««««««««««««««¬««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­¬­¬¬­¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬«¬¬¬­¬«¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬««­«««««««««««««««««««««¬¬¬«««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­¬¬­­¬­­¬­¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬«­«««««««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­¬¬¬­­¬­¬¬¬­¬¬­¬¬¬®¬¬¬¬¬¬¬«««««««¬«««««««««««««««««««««««««««««««««««««««««««««««¬¬««®¬­««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­¬¬¬¬¬¬­¬¬­­¬­¬­¬¬®®®¬¬¬¬¬«¬¬­¬¬¬¬­¬««¬«««««««««««««««««««««««««««««««««««««««««««««««¬«¬«¬­¬¬««­¬«««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬­¬­¬¬­¬¬­­¬¬¬­­®®®­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬­««®¬«««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®­­­­¬¬¬­¬­­­¬­¬­­­¬®®®­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­­¬¬¬«®««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬¬­¬¬­¬¬¬­¬¬­­¬¬®¬­¬¬­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««««¬«««­¬¬¬¬««¬­«««««««¬««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­®­­¬­­¬¬­­¬­¬­¬¬­¬­­¬¬¬¬­¬¬¬­¬¬­­­¬¬¬¬¬«¬««««««­««««««««««««««¬««««««««««««««««««««««««««««««««««««««««­­««®¬«««««««««¬«««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­¬¬­¬¬­¬¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬­¬¬«¬¬¬¬««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­­­¬¬­¬­¬­¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬«¬«¬­«««««¬««««««««««««««««««««««««««««««««««­««««««««««¬¬­¬¬¬¬­««««­­¬¬«««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­­¬­¬­­¬­¬¬­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬«««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬¬¬¬«®¬­««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬¬¬¬¬¬­­¬¬¬­¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬«¬««««¬««¬«¬­«««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬­¬­««­®­¬¬««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬®®¬­¬¬­«¬¬¬¬¬¬­­­¬¬¬¬¬­¬««««««¬«««¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬­¬¬««®¬¬¬¬««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬¬¬¬¬­­­­¬­¬®­¬­¬­¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬­®¬¬¬­¬¬«««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­«««¬®¬¬««««¬««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­­­¬­­­­¬­¬¬¬¬®®¬¬­­¬¬¬¬­¬¬¬¬¬­­¬¬¬¬­¬­¬­««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«««««««««««««¬««­­««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬­¬¬­¬¬­¬¬­¬­­®¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­¬¬¬­­¬¬­¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬®­¬­¬¬«««««««««¬«««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬¬¬­­¬­­¬¬¬­¬®®®¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­­­¬­¬¬¬­¬­¬«¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬®¬¬««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬­¬­¬­¬­­­¬­­­¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬­¬¬­¬­¬¬­¬«««««¬«««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬®¬¬¬¬«««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬­¬¬­¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬­­­­­­¬¬¬­­­¬­¬­¬¬¬¬«««««««««¬«««««««««««««««««««««««««««««««««­«««¬«««««««««««««««¬¬­®¬­¬«¬«««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­¬­­­­­¬¬­¬¬­¬­¬¬­¬¬¬­¬¬­­­­¬­­­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­­¬«««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬¬¬¬­¬­­¬­­­­¬¬¬­¬¬¬­­¬¬­­¬¬¬­¬¬­­¬¬¬¬¬­¬¬««««¬««««««««««««««««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««­­¬¬¬¬««««««««««««««««««¬«®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬­¬­¬¬­­¬¬­¬¬­¬¬­­¬¬¬­¬¬­¬¬¬¬¬­¬­­¬¬¬¬­¬¬­­¬¬­¬­¬««««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««¬¬¬®¬«««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­¬­­¬­¬¬­¬¬­¬¬­­­¬¬­¬¬¬¬­¬¬¬¬­­¬¬¬¬­¬¬­¬¬¬¬¬¬­¬­­¬­­¬««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬««««­­­¬««««««««««««««««««««««««««®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­®­­­¬¬­¬¬­¬¬­¬¬¬­¬¬­¬­¬¬­¬­­¬¬­­¬­¬¬¬¬­­­¬­¬¬­­­­­¬¬¬««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««¬¬«¬««­¬«««««««««««««««««««««««®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬­¬­¬¬­¬¬­¬­¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬­­¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬««««««««««««««««¬««««««««««««««««««««««««««««««««««««««¬«­¬­«««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬¬­­¬¬­¬­¬­¬¬­­­¬¬­­¬­¬¬¬­­­¬­¬¬¬¬­­­¬­­­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««­«««««««««««««««««««¬««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬¬­­­¬¬­¬¬­­¬¬­¬¬¬¬­¬¬¬­¬¬¬­¬¬­¬­¬¬¬¬¬­¬­¬¬­¬­¬¬­¬­­¬­­­¬¬««««««««««««««««««««««««««««««««««««««««««««««««««¬¬­¬««««««««««««««««¬««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­¬­¬¬­­­¬­¬¬­¬¬­­®­¬¬¬­­¬¬¬­¬¬­¬­¬¬¬­­¬¬¬­¬¬¬¬¬¬«¬««««««««««««««««««««¬«««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­­¬¬­¬­­¬­¬¬­­¬¬¬­¬­¬­¬¬­­¬­¬¬­¬¬¬¬­­¬­¬­¬¬¬¬­¬¬­­¬¬¬¬««¬«««««««««««««««««««««««««««««««««««««««««««««««¬««««««««««««¬«««­­««¬««««««««««««««««««¬«««¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬­­­­¬¬¬¬­¬¬­¬¬®¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬­¬¬¬«««««««««««««««­«««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬­«¬««««««««««««««««««««««¬¬­¬¬¬¿¿¿1¿1¿¿¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­­­­­­­¬¬¬¬¬¬­¬­¬¬¬¬­¬¬­­¬­¬­¬¬­¬¬¬¬¬­¬¬­­¬­¬¬¬¬­¬¬­¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««®¬««¬«««««¬««««««««««««««««­¬¿1¿11¿1¿11¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­®­­¬¬¬­¬­¬¬¬¬¬¬­¬¬¬¬®®®¬­¬¬¬­¬¬­¬¬¬¬¬¬­¬­¬¬¬¬¬¬­­«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­¬¬¬««««««««««¬«««««««««««¬¿¿1¿¿¿11¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬¬­­¬­­­­­¬¬­¬­¬­­¬­¬­­¬­¬¬­¬¬¬¬­­¬¬­¬¬¬«¬«««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««««««««««««««««««­«¬«««««««««««««««««««««««««««¬¬«¬1¿¿1¿¿1¿¿11¿¿¿1¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®­­­¬¬­¬¬¬­­¬¬­­¬¬¬­®­­¬¬­¬­¬¬­¬­¬¬­¬¬¬¬¬¬­¬­¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­««««««««««««««­¬¬«««««««««­¬¬¬¬¿¿11¿¿¿1111¿¿¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­¬¬­­­¬¬¬¬¬¬­¬¬­¬­¬­¬¬¬¬­¬¬­­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬««««««««««««««««««««¬«««««««««««««««¬««««««««««««««««««««««««««««««««««««««««­¬«««««««««««««¬¬­««««««¬1111111¿¿1¿11¿¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­¬­¬­¬¬¬­­¬¬¬¬­¬¬­¬­¬¬¬¬­¬­¬¬¬¬¬¬­¬­¬¬¬««««««««««««««««««««««««««««««««¬««««««««««««««¬«««¬«««««««««««««««««­¬­««««««««««««­«««¬¬¿¿111111¿¿11¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­­¬­­­­­­¬¬¬¬¬­¬¬­¬¬¬¬­¬­¬­¬¬¬­­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬«¬««««««««««««««««««¬¬¬¬¬¬¿¿11¿1¿¿¿1¿1¿11¿¿1¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­¬­­¬¬¬¬­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­­­¬­­¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««­«««««««««««««««««««««««««««««««««««¬¬«««««««¬«««««««««¬«««««««««¬¬¬­¬¿¿¿1111¿1¿¿¿¿11111111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬¬­¬¬­¬­¬¬­¬­¬¬­¬­¬¬­¬¬­¬­¬¬¬¬¬¬­¬¬¬­­­¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««««­¬¬««««««««««««««««««««¬¬«¬¬­¬¬«111¿¿11111¿1¿¿11111111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­®­¬¬­­®¬­¬¬¬­¬¬®­¬¬­­¬¬­¬¬­¬­¬¬­­¬¬­¬¬¬­¬¬­¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬«««««««««««««««««««««««­¬«1¿¿11¿11111111¿¿1111¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬­¬¬­¬¬¬¬­¬¬­­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬««¬««««««««««««««««««««««««««««««««««««««««««¬««««««««­««««««««««««««««««¬¬¬«««««««««««¬«¬«««««««¬¿¿1¿1111¿¿11¿¿1¿1111111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­¬­¬¬­¬¬¬­¬­¬¬­¬¬­¬¬¬­¬­¬­¬­¬¬­¬¬¬­­¬¬­¬­¬­­¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬«««««««¬««««««««««­¬¬1¿¿1¿¿1¿¿1¿111¿11111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­­¬¬¬¬¬®­­­¬¬­¬¬­¬­¬¬­­­¬¬¬¬¬­­¬¬¬­­¬­¬¬¬¬¬¬¬¬­¬¬¬­«¬¬¬«¬«««««««««««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««¬­«¬¬«««««««««««¬«««­«««««««¬¬¬­¬«¿¿¿11¿1¿¿111¿1111¿¿1¿¿¿1¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬­¬¬­¬¬­¬¬­­¬¬­¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬«¬¬«««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««¬¬««««««««««¬«««««««­¬¬¬«1¿1111¿¿1¿1111¿¿¿¿¿¿1¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­®®­­¬¬­¬¬­­¬­¬¬­¬¬­¬¬¬¬¬­­­®¬¬¬¬¬­­­­¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬­­¬«««««««««««««««««««««««¬¬¬¬¬¬¿¿¿¿¿¿¿¿¿¿111¿¿¿1¿1¿¿1¿¿¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬¬¬®®¬¬¬¬­¬¬­¬¬­­¬¬¬¬­¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬­¬­¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­¬««««««««««««««¬««««¬¬¬¬1¿¿¿¿¿¿1¿11¿11¿¿11¿1¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­¬­­¬¬­­­¬­¬¬­¬¬¬¬¬­¬¬¬¬¬­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««««««««««««««««¬¬¬¬¬¬¬«««««««««««««««¬¬¬¬«­¬¬¬¿¿¿¿¿¿11¿11¿¿¿1¿1¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®­­®®­¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬­­¬­¬¬¬­­¬­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬«¬«««««««««¬¬¬¬¬¬­¬¬¿¿111¿¿¿¿¿¿¿1¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­®­¬¬¬­­­¬¬­­¬¬­¬¬­¬¬­¬­¬¬­­¬¬­­¬¬¬¬¬¬­­¬¬­«¬«««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««¬¬««««««««««««««««««««««¬­¬««««««¬«««««­«¬¬¿1¿¿1¿¿¿11¿¿11¿¿1¿¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬­¬­¬¬­¬¬¬¬¬¬¬­¬¬¬­¬­¬¬­¬­­­¬­­¬¬¬¬¬¬¬¬­¬¬««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«««¬­¬¬¬¬¬¬««««««««««¬¬¬¬¬¿¿¿¿¿1¿¿¿¿¿1¿¿1¿¿1¿¿1¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬­­­¬¬­¬¬¬­¬­­­®­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬««««««««¬¬­¬«­«¬­¬¬¬­¬¿¿¿¿¿¿¿11¿¿¿1¿¿1¿¿¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­­­¬®¬¬¬­­¬¬­­­¬¬­¬­­¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬¬¬¬¬¬¬¬«««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬««««¬¬««««««««¬­««««¬¬¬¬¬¬¬¿¿¿¿11¿¿¿¿11¿¿¿¿1111¿111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬®­­¬­¬­­¬¬¬­¬¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬«««¬¬¬«««««¬¬««¬¬¬¬¬¬¬¬«¿¿111¿¿1111¿¿¿¿¿1¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®­®®®¬­­¬¬­¬¬¬¬­¬¬¬¬­­¬­¬¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬««««««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬¬««¬¬­¬¬¬«««««¬««¬¬¬¬¬¬¿111¿¿¿¿¿¿¿¿¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®­®­­¬­­­­¬­¬¬­¬­¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«­¬¬¬¬«««««««««¬¬««««¬««¬¬¬¬¬¬¬1111¿¿¿¿¿¿111¿¿¿11¿®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬­¬¬¬­¬­¬¬­¬­¬¬¬¬¬¬­­¬¬­¬¬¬¬¬­¬¬¬«««¬««««««««««««««««««««««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬­­¬­««««««««««««««­¬¬¬¬¬¬¬¿1111¿¿¿¿¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­­¬­­¬­¬¬­­¬¬­­¬¬­¬¬­­¬¬¬¬¬¬¬¬­¬¬¬««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««¬­¬¬­«««««««««««¬¬¬¬¬¬¬¬­¬111¿¿¿11¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®­­­­­­¬­­¬¬¬­¬­­¬¬¬¬¬­­¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««¬««««««««««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««««¬¬¬¬¬­¬¬««««¬«««¬«««««¬¬¬­¬¬¬­¬¿¿11¿¿¿111¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬­¬¬¬¬­­­¬¬¬¬¬¬¬¬¬­¬¬­­­­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««¬«««««««««««««««¬«««««««««««««««««««««««««««««««¬««¬¬¬¬¬¬¬««««««««««««¬¬¬¬¬¬¬¬­¬¬¬¿¿11¿¿¿¿11¿¿11¿¿1¿¿¿®®®®®®®®®®®®®®®®®®­®®­®®­¬¬¬¬­¬­­¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«««¬«««¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««­««««««««««¬«««««««««««¬¬¬¬¬­­¬««««««««««««««««¬¬¬¬¬¬¬­¬¿11¿¿¿¿¿1¿1111¿¿¿¿¿¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬¬­¬­¬­¬­­¬¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««­«««««««««««««««««««««««««««««««««««««««¬¬¬­¬¬¬­­¬¬««««««««««««««««««¬¬­¬¬­¬¬¬¬¬­¬1¿¿¿11¿¿¿¿1¿111¿¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­­­¬¬­­¬¬­¬¬­¬­¬¬¬¬­­¬­¬¬¬­¬­¬­¬¬¬¬¬¬­¬­¬­¬¬¬¬«¬«««««««««««««¬¬¬¬«««««««««¬¬­¬¬¬¬««««««««««««««««««««««««««¬««¬««««««««««««««­¬¬¬­¬¬««««««««««¬­¬¬­­¬¬«1¿¿¿111¿11¿11¿111¿®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬¬¬­­¬¬¬¬­¬­¬­­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬«¬¬«««««««««««««««««««¬««««««««­«««««««¬«¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««­­¬­¬¬««««««««¬¬¬¬¬¬­­¬¬1¿¿¿11¿¿¿111¿11¿11¿¿1¿¿¿¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬­­­¬¬¬­¬¬¬­¬­¬¬­¬¬¬¬¬¬¬®­­¬­¬­¬¬¬¬¬¬¬«¬«««««««««««««««««««««««¬¬«¬¬¬¬«««««««««««««¬­¬¬¬¬««««««««««««««««««««««««««««­«««««««««««««¬¬¬­¬­««««¬­¬¬­¬¬¬¬¬¬1¿¿¿¿¿¿111¿11111111¿¿¿¿¿¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬­¬­¬¬¬¬¬­¬­­­¬¬¬¬­¬¬­¬¬­¬¬¬¬­¬­¬¬¬¬­¬­¬¬¬«­««««««««««««««««««««¬«««««««««««¬­­¬¬¬­¬««««««¬«««««««««««««««««««««««««««««««­¬««««¬«¬¬¬­¬¬¬¬¬¬1¿¿1¿¿¿¿¿¿11¿1111¿¿1¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­¬­­­­¬­­¬¬¬¬¬­¬¬¬­¬­¬¬­­¬­¬­­­­¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬«¬«««««««««««««««««¬¬««¬¬¬¬¬««««««««­­¬¬¬­­«¬««««««««««««««««««««««««««««¬«¬«¬«««««¬«««««««¬«¬­«¬«««««¬¬¬¬¬¬¬­¬¬¬1¿¿¿1¿1¿1¿111¿¿¿1¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®®­­­­­¬¬­¬¬­­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­­¬¬¬¬­¬­¬¬­¬­­¬¬¬¬¬¬«««««««««««««¬¬¬¬¬¬««««««««¬¬¬­¬­­««¬¬««««««««««««««««««««««««««««««¬¬¬««««««««««­«¬­««««««¬¬«­¬¬¬¬¬11¿1¿11¿¿1¿¿¿1¿1¿¿11111¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­­¬¬­¬­­­¬­­¬¬¬¬¬¬­­­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­­®¬¬­­¬­¬¬¬¬«««¬¬««««««««¬««¬«¬­¬««««««««««¬­­¬­¬­¬«««¬««««««««««««««¬«¬«««¬«««««««««««««««¬¬¬«««¬¬¬¬¬¬11111111¿¿1¿1¿¿11¿¿¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­­¬­­­¬­¬­¬­¬¬­¬¬¬­¬¬¬¬¬­¬­¬­¬­®­¬­­¬¬­««««­««««««««««««««««¬¬¬¬««««««¬«¬¬¬¬««««««««««««««««««««««¬¬¬¬«««««««««««««««««¬¬«­«¬¬¬«¬¬¬¬¬¬¬­1111111111¿¿111111¿11¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬­¬­¬¬¬¬­¬­¬¬­¬¬¬­¬¬­­­¬¬¬«««««««««««««««««««««««««««­«­­¬¬««««««««««¬¬«««««««««««««««««««««¬«««««««««««««««¬¬®¬¬¬««««­¬¬¬¬«111111111¿11¿¿111¿111¿1¿®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬­­¬¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­­¬¬­¬­¬¬­¬­¬¬­¬­¬¬««««««««««««««««¬¬¬¬¬«¬¬¬¬¬««««««««««¬¬¬¬««««««««««««««««««««¬««««««««««««««««««¬¬¬««««««­¬¬¬¬­¬¬111111111111¿¿¿¿¿¿¿1¿1®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬¬¬¬¬¬­­¬¬¬­¬¬­­¬­¬­¬¬¬­¬­¬¬¬­¬¬­­­¬¬¬­¬­­¬¬­­¬¬¬¬¬­««««««««««««««­­­«¬¬««««««««««««««¬­«¬««¬¬««««««««««««««««¬««««««««««««««««­««««««««¬¬¬¬¿111¿1111¿¿¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®¬­­®­¬¬­¬­­­¬¬­¬¬¬­¬¬¬¬­­¬­¬¬¬¬¬¬¬­­¬­­¬¬­­¬­­­¬¬¬­««««««««¬«««««¬¬¬¬¬¬­¬¬««««««««««««¬¬«««¬««««««««««««««¬««««««««««««««««««¬¬«««««««««¬¬¬¬¬­«¿111111¿¿¿¿¿¿¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬­­¬­¬¬¬¬¬­¬¬­­­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬«««««««««««¬¬¬¬¬­¬¬­­¬««««««¬««¬¬­­¬­­¬««««««««««««««««««««««««««««««««««««««««««­¬¬««««««««¬«¬¬¬¬11111111¿¿¿11111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­¬¬¬¬­¬¬¬­¬¬­¬¬¬¬­¬­¬¬¬­­¬­¬­¬­¬­­¬­¬­¬¬¬¬¬¬­«¬¬««««««««««««««¬­¬¬¬¬«««¬¬««¬¬¬¬««««¬«¬««««««««««««­««««««««««««««««««««««««¬¬¬«««««««««¬¬¿1111111¿¿11111®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®­­­­¬¬­­­­­­­¬¬¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬¬­¬¬¬­­¬­¬¬¬¬­­­¬¬¬¬­¬«««««««««««««««««¬«¬­¬¬¬¬««««««««««­¬¬¬«¬­­¬«¬¬««««««­««««««¬¬«««¬«««««««««««««««¬¬­¬«««««««««¬««¬¬¬¬¬¬¬11111111¿¿¿¿¿¿¿¿1111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬¬¬¬­¬¬­¬­¬¬­­¬­¬¬­¬¬­¬¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬««««««««¬«««««««««¬¬­­¬¬¬¬«««««««¬­¬­­«¬«¬«««««««««««««««¬«««««¬««««««««««««««­­««««««««««««¬¬1111111¿11¿¿¿¿¿®®®®®®®®®®®®®®®®­®®®®®®®®®®®®­¬­­­­¬­­­­­¬¬¬¬¬¬¬®­­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬««««««¬¬¬­¬¬«¬«««««««¬¬­«¬­¬«««««««««««««¬«««««««««««««««¬«­¬¬¬«««««««««««««¬¬«¬¬1111111¿¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®­®®®®®®­­¬¬­¬¬­¬­¬­¬­¬¬¬­¬­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬¬¬«¬¬¬¬¬¬¬¬«««««¬««««¬­¬««¬¬¬¬«««««««¬­««¬«««««««««««««««««««««¬­¬¬¬¬«««««««¬¬¬¬­11111111¿11¿11¿®®®®®®­®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬®­­­­¬¬­­¬¬¬¬­¬­¬¬¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬««¬««¬¬¬¬¬¬¬­¬««««««¬¬¬¬¬««¬¬«««««««­¬««««««««««««««««««««««««««­¬¬¬¬­««««­¬¬¬¬¬¬­11111111¿11¿11¿1®¿®®®­®®®®®®®®®®®®­®®®®®®®®®®®®®®®­®­®®­­¬­­­¬¬¬­¬¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬««¬«¬¬¬­­¬¬¬¬¬«««¬««««««««¬¬«««­««¬«««««««««««««¬«««««««««««««««««««­¬¬¬¬«««««««¬¬¬¬¬¬¬¬¬111111111111¿¿11¿®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬­¬¬­¬­¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬­¬¬««««««««««¬«¬­¬¬««««««««««««««««««««««««««««««¬¬¬¬¬¬«««««««««««¬¬¬¬¬¬¬¬¬11¿11111111111¿1¿¿®®®¿®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬­­¬¬¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬¬­¬­¬­¬¬¬¬­­­¬¬¬¬­¬¬¬¬­­¬¬­­­«¬¬­¬¬¬¬­¬¬¬«««««««««««««­¬«««¬¬¬¬««««««««¬«««««¬««««««««««««¬¬¬¬¬¬««««««««««««««¬¬¬¬¬¬¬1111111111¿¿1¿¿¿®®®®®­®®®®®®®®®®®®­­®®®®®®®®®®®­¬¬­­¬¬¬¬¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬««««««««««««­««­¬««¬«««««««««««««««««««««««««««««¬­¬­¬¬­­¬­«««««««««««¬¬¬¬¿1111111111¿¿¿¿¿®®®®®®®®®®®®®­®®®®®®®®­®®®®¬¬¬­¬­­¬¬¬­¬¬­¬¬¬¬­­®­­¬¬­­¬¬­­¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬««­¬¬¬¬¬¬­¬­¬¬«««««««¬««««««¬¬««««««««««¬««««««««««««««««««¬¬¬¬¬­¬­¬¬¬«««««««««¬¬¬¬¬¬¬¬¬¬11111111111¿¿¿¿1¿¿¿¿®®®®®®®®­­®®­®­­®®®­®®®®®®®®®®®­­¬¬­¬­¬¬¬­¬¬¬¬­¬¬¬­­¬­­­­¬­¬¬­¬­¬¬¬¬­­¬¬¬­¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬«¬¬¬¬¬¬¬­­¬¬¬¬«««««««««««¬¬¬«««««­¬«««««­«««««««««««««««««««««¬¬¬­¬¬«««««««««««¬¬¬¬1111111111¿¿1¿¿¿11¿¿¿®®®®®®®®®­®®®®­®®­®®­­®­®®­®®®®®®®®®­¬¬­­­¬¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬««««¬¬¬¬¬¬­««««««««¬¬««¬¬¬¬¬««¬«¬¬«««««««««««­«««««««««««««««««««¬¬¬¬¬¬¬«««««««««««««««««¬¬­«¬¿11111111¿1¿¿¿¿¿¿¿®®®®®®®®®®®®­®­®®®­­®®®®®®­­­®¬­­¬¬¬¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬¬««««¬¬¬¬¬¬¬¬««««««««««««««­¬¬««««¬¬¬¬¬«««««««««««««««««««««««««««««««¬­¬¬¬¬­««««««««««««««¬¬¿111111111¿¿1¿¿¿®®®®®®®­®®­®®®®®®®­®®®®®®­¬­­­¬¬¬­¬¬¬¬­­¬¬­¬¬­¬¬­¬¬¬­¬­­­¬­¬­¬¬¬­¬¬¬¬¬¬«««¬¬«¬¬¬¬¬¬««««««««««««¬¬¬«««««­«««««¬«««««««««««««««««««««¬¬¬¬¬­¬¬«««««««««««««««¬¬¬1111¿11111¿¿¿¿¿¿¿®®®®®®®®­®­®®®®­®®®®®®®®®®®­­­®¬¬¬¬¬¬­¬¬¬¬­¬¬­­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬«¬¬¬¬¬««««««««««¬««¬¬«¬«««««««««««««««««««««««««««¬«¬¬­®¬¬¬­­¬¬¬«««««««««««¬¬¬¬¬«1¿1¿¿111¿¿¿1¿¿1¿¿®®®®®®®®®®®®®®­®®­®®­®®­­¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬­¬¬­¬­¬¬­¬­­­¬¬­¬¬­¬¬¬¬¬­­­¬¬¬¬¬¬«««¬¬¬¬¬­¬¬¬¬¬¬¬«¬«««««««««««¬¬««­¬¬«¬««¬««««««««««««««¬«««««««¬¬­¬¬¬«««««««««««««««¬¬¬¬¬¿1¿¿¿¿¿¿¿¿¿¿¿®®®®­®®®®®®®®®®­®­­®®®®®®®®­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬­­¬¬¬­¬­­¬¬¬­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««¬¬­¬­­¬¬­«««¬¬««¬«««¬¬¬¬­««««««««««««««««««««««««««««¬¬¬¬­¬¬¬¬­¬«««««««««¬¬¬¬¬¬¬¬111¿¿1¿¿¿1111¿11®®®®®­®®®®®®®®®®­®®®®®®®®®®®­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬¬­­­¬¬­¬¬¬¬¬¬¬¬«¬¬¬¬¬­¬«««««««¬««­¬¬«¬­¬««««««««««««««««««««««««««««««¬­­¬¬­¬««««««««««««««¬­¬¬11¿¿11¿11¿¿11¿1¿¿¿¿¿¿¿®®­®­­­®­®­­­­­­­­­­­®®®­®­®®®®­¬¬­¬¬­­­¬­¬­¬¬¬¬­­¬¬­¬¬­¬¬­­¬¬­¬¬­¬¬¬­¬­¬­¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬«¬«¬¬¬¬¬¬¬¬¬¬¬­¬¬««««««««««««««««««¬­¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬111111¿11¿¿¿¿1¿111¿¿¿¿®®­­®­­­­­­­­­­­­­­­­®®®­®®®®®­­­­¬¬¬¬¬¬¬­¬¬¬¬­¬­­¬¬­¬­­¬­¬¬¬¬­¬¬­¬¬¬­¬¬­¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬«¬¬¬¬¬­¬¬¬¬¬¬¬««««¬«««¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««¬¬­­¬­¬¬¬­¬­­­¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬1111111111¿¿11¿11¿¿¿®®­®®­­­­­®­­­­­­­­­­®®®®®®¬®­­¬¬­¬­­¬­¬¬¬­¬¬­¬­¬¬­¬­¬­¬­¬­¬¬­¬¬­­¬¬­¬­¬­¬¬¬¬­­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬«««¬««««««««¬¬¬¬­¬¬­­¬¬­­¬¬¬¬«««««««««««««««««««««««««««««¬¬¬­¬¬­¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¿1111111¿¿111¿1¿¿¿®­®­­®­­­­­­­­­­­­­­­­­­®®®®¬­­¬­­¬­¬¬¬¬¬­­¬¬­­¬¬¬­¬¬­¬­¬­¬¬­¬¬­¬­¬­­­¬­¬­­¬­­¬­¬¬¬­¬¬­¬¬­¬¬¬¬¬­¬«¬¬¬¬¬¬¬¬¬¬¬«««««««¬¬­««¬¬¬¬¬¬¬¬¬¬­­¬«««««««««««««««««««««««««««««««¬­¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬111111¿¿1111¿¿¿¿¿¿®®®®®­­­­­­®­­­­­­­­­­­®®­®®®®¬¬­­­­­¬­­¬­¬¬­­¬¬­­­¬­¬¬¬¬­¬¬¬¬¬¬¬­¬¬­­­­¬­¬¬¬­¬¬¬¬­­¬¬­¬¬¬­¬­¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬««««««¬«««««¬««¬¬­¬­­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬1111¿¿¿1¿11¿¿1¿111¿¿®®®­­­­®­­­­­­­­­­­®­®®­®®®®®®®¬­¬¬­­¬­¬­­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬­¬­¬¬­­­¬­¬­¬¬¬­¬­¬¬­­¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬«¬¬¬¬¬¬¬¬¬¬««««««««««««««««¬«««¬¬¬¬¬¬¬¬­¬¬¬¬¬¬««««««««««««««««««««««««««««««««««¬¬­¬¬­¬­¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬1111¿1¿¿1111¿¿1¿111¿¿¿1®¿®®­­­­­®­®®­®­­­­­­­­­®­­­­®­­®­­¬¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬­¬­¬¬­¬¬­¬­¬­­¬¬­¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­«¬¬¬¬¬¬¬¬¬¬¬««¬«««¬««««¬¬­¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««¬¬¬­­­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬111111¿¿11¿¿1¿1¿¿¿¿¿¿¿1®¿®®®®®®®­­­­®­­®­­­­­­­­­­­­®­®®­¬­­­¬¬¬­¬­¬¬­¬¬­¬­¬­¬¬¬­­¬¬­­¬­¬¬­­­¬­¬¬­¬­­¬¬­¬¬­¬­¬¬­¬¬¬¬­¬­¬¬¬¬­¬«««¬¬¬¬¬¬«««««««¬««««¬¬¬¬¬¬¬­¬¬¬¬¬«««««««««««««««««««««««««««««««¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬11¿1¿111111¿¿¿1¿1¿¿®®®®®®®­­­­­®®­­­­­­®­®®­®­­®­¬­­¬¬¬¬­¬¬­¬¬­¬­­­¬­­¬¬¬­­¬­¬­¬­¬¬­¬­¬­¬¬­¬­¬­­­­­¬¬¬¬­¬¬¬¬¬¬¬¬«¬¬¬¬¬«««««««««««««­¬¬¬¬¬­¬¬¬¬¬¬¬«««««««««««««««««««««««««««­¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¿1¿1¿11¿1111¿¿¿¿¿¿®¿¿1¿®®®®®®­­­­­­­®­­­­­­­­­­®­®­®­®®®®­­¬¬­­­¬¬­¬­¬¬­¬¬­¬¬¬­¬¬­­­¬¬­¬­¬¬­­¬¬­­¬¬­¬¬­¬¬¬­­­¬¬¬­­­­«¬«¬¬¬¬¬¬¬¬­¬¬¬¬«¬«««¬«««¬«««¬««­¬­­­¬¬¬¬¬­¬«¬««««««««««««««««««««««««««««­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¿1¿11111111¿¿¿¿¿®®¿®®®®®®­­­­­­­­®­­­­­­­­®­®®­®®®®®®­­­¬¬­­­¬­¬­­®¬­­¬¬¬­¬­¬¬­¬¬­­¬¬¬¬¬¬¬¬­¬¬­­¬¬­¬­¬¬­¬­¬¬­­®­­¬­¬®®¬­¬¬¬¬«¬¬¬¬¬¬¬­¬¬¬««««¬««¬««¬­­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬««««««««««««««««««««««««««¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬­­­¬¬­¬¬¬¿¿1111111111111¿111®®®®®®­­­­®­­­­­­®®®®®®®®®®­­­­­¬­¬¬¬­¬¬­­­­­­­¬­¬¬¬­¬­­¬­­­­¬¬­­­­¬¬¬­¬¬­¬­­­¬¬­¬­¬¬®¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««­¬¬«¬¬¬¬¬¬¬­¬¬¬¬¬¬«««««««««««««««««««««««««««®¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­­¬¬¬11111111111111¿¿¿1¿®®®®®®®®­­­­­­­­­­­­­­­­­®­®®­­®®®®®­­­¬­­¬¬¬¬­¬­¬¬¬¬­¬­¬¬­­­­¬¬¬¬¬­¬­­¬¬­¬­¬¬¬­­¬¬­­¬­­¬¬¬­¬¬­­¬­¬¬¬¬­­¬¬¬¬¬­¬¬¬¬¬«««««««««««¬¬«¬¬¬­¬­­­­¬«««««««««««««««««««««««««««««««««­­¬¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¿111111111111¿¿¿¿11¿®®®®®®®®®®®­­­­­­­­­­­­­­­­­®®®­­­­®®®­­­¬¬­¬¬­¬¬¬¬­¬­¬¬­¬¬­­¬¬¬¬­¬¬­¬­¬­¬¬­¬¬­¬¬­¬¬­¬­¬­¬­¬¬­­¬­¬­¬¬¬­¬¬¬¬­­¬¬¬¬¬¬«¬¬¬¬¬¬¬¬«««««««««««¬¬¬¬¬¬¬¬¬¬¬¬­­«««««««««««««««««««««««¬«¬¬¬­­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬1111111111¿111¿1¿1¿¿1®®®®®®®®®®®­­­­­­­­­­­­­­®­­®®®®®®­®®®®®­¬¬¬¬­¬¬­¬­¬­¬¬¬­¬¬­¬­­­¬¬¬¬¬¬¬­¬¬¬­¬­¬­­­¬¬¬¬¬¬¬¬¬­­¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬««««««««««««««««««««¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬®¬¬«««««««««««««¬«««««««««««««««¬¬­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¿11111111¿11111¿¿1¿¿1¿®®®®®®®®­­­­­­­­­­­­­­­­­­®®®®®®®­®­®®®®¬­¬¬­­­¬¬¬¬­¬­¬¬­­­­¬­¬­¬­¬­¬­­¬­­¬¬­­¬¬­¬­­¬¬¬­¬­¬¬­¬­­¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««¬¬¬¬­¬¬¬¬¬¬­¬««««««««¬«««««««««««««««««««­¬¬¬¬­­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¿1111¿¿1111¿1¿1¿®®®®®®®®®®®®®®®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬­­¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬­­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬­­­¬¬­­­­­­¬¬¬¬­­¬¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬­¬­­­¬­¬¬¬­­¬¬¬«««««««««««««««««««¬¬¬¬­¬­­¬¬¬¬¬««««««««¬«««««««««««¬¬¬¬¬­­­¬¬¬¬­­­¬¬¬­¬­¬¬¬¬¬­­­¬¬­¬¬¬­­¬¬­¬¬1111111¿1¿¿11¿¿1®®®®®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®¬¬­¬¬¬¬¬­¬­¬¬¬¬¬¬­¬¬¬¬­­­­¬­¬­­¬¬¬¬­¬­¬¬¬¬­¬¬¬­­¬­­­­¬¬¬­­­­­¬¬­­¬­­¬¬¬¬¬¬¬­¬­¬¬¬­¬­¬¬¬¬¬­­­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬««««««««««««¬«¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««¬­¬­­¬¬­¬­¬­¬­¬¬¬¬¬­­¬¬¬¬¬­¬¬­­¬¬­¬¬­¬¬¬¬­¬­¬¬1111111¿1¿1¿¿1¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬¬­¬­¬­¬¬­¬¬¬¬¬¬­¬­­¬¬­­­¬­¬­¬­¬­­¬¬¬­­­­­­­¬¬¬­­¬¬¬¬¬­¬­¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­­¬­¬¬¬¬¬¬¬¬««««««««««««««««¬¬­¬¬­¬¬¬««««««««««««««««««««««««««««««««««««¬­¬¬­­¬¬¬¬­¬­¬¬­¬¬­¬¬¬­­­­­­¬­­¬­¬¬¬¬¬¬­¬­¬¬¬­¬­­¬¬¬­¿11111¿¿¿1¿¿11¿®®®®®®®®®®®­­­®®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬­¬¬­¬¬¬¬¬­¬¬­¬¬­­­­­­¬¬­¬­¬¬­¬­¬¬­¬­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬­­¬¬¬­¬¬¬¬­¬¬­¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««¬¬¬¬¬¬­¬¬«««««««««««««««««««««««««««¬¬¬¬­¬¬¬¬¬­¬¬¬¬­¬­­¬¬­­¬­¬¬¬¬¬¬­­¬¬¬¬­¬­¬¬¬¬­­¬¬¬­¬¬¬¬1111¿¿1¿¿¿¿¿¿11¿¿1¿®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬¬­¬­¬¬­¬¬¬¬­¬­­­­®­­¬¬­­­­¬¬­­¬­­¬¬¬­¬­­¬¬¬­­¬­¬­¬­¬­¬¬­¬¬¬­¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬¬­­¬¬¬¬¬­­¬¬­«««««««««««¬­¬­¬¬­¬¬¬¬¬­¬«««««««««««««««««««««««««««««««¬¬¬­¬¬­¬­¬¬­¬­­­¬¬­­¬¬¬¬­­­­­­­¬¬¬¬¬¬¬­­¬¬­­¬¬¬¬¬¬­¬¬­¿¿1¿¿1¿1¿¿¿1¿¿¿¿®®®®®®­®®®®®®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­­­¬¬¬¬­¬¬­¬­¬¬¬¬­¬¬­¬­­­­­­­¬¬¬¬­¬¬­¬¬¬­¬­­­­­­­­¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬­¬¬­­­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬««««««««««««««¬««­¬¬­¬¬¬¬¬¬­¬«««««««««««¬««««««««««««««««««««¬¬­¬¬­¬¬­¬¬­¬¬­¬¬¬¬­¬­¬¬¬¬­¬¬­­­­­­­¬­¬¬¬­­­­¬­¬¬¬¬¬¬¬¬11¿1111¿¿¿¿¿¿11¿®®®®­®­®®®®®®­­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­­­­­­¬¬­¬­¬¬¬¬¬¬¬¬¬­­¬­®­­¬­¬¬¬¬­¬­¬¬­¬®­­­­­­¬¬¬­­¬¬¬¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬­­¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬«««««««««««««««««¬¬«¬­¬¬­¬¬¬¬¬«««««««««««««««««««««««««««­¬­¬¬¬­¬­¬¬­¬¬­¬¬¬¬­¬¬­­¬­¬¬¬¬­¬¬­¬­­­­¬­­­¬¬­¬­­¬­­¿111¿1¿¿11111¿®®®®®®®­®®®®®­®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­¬­­¬­­¬¬¬­¬¬¬¬­¬¬­¬­¬­­­­¬¬¬¬¬­¬¬¬­¬­¬­­­­­­¬¬¬¬­­­¬¬­¬¬­­­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬­­­­¬¬­­­¬¬­­¬¬¬¬­¬¬¬­««««««««­­¬¬¬¬¬­­¬¬¬¬¬¬«««««««««««««««««««««««««¬­¬¬­¬¬¬­¬¬¬¬­¬­­¬¬¬¬­¬¬¬­¬¬­¬­¬¬­¬¬­­¬¬­¬¬­­¬¬¬¬¬¬­¬­­¬¬­1111111111¿¿1¿¿®®®®®®­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬­­­®®¬­­¬¬¬­¬¬¬¬¬­­¬­¬­­¬­­¬­¬¬­­¬¬­¬¬®®­­­­¬¬¬­­¬¬¬­¬¬¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬¬­¬¬¬­¬¬­¬­¬­¬¬¬­­¬¬­¬¬­¬¬¬¬«««««««««««­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««¬¬¬¬¬­¬­¬¬­¬¬­¬­¬¬¬­¬­¬¬¬­­­­¬¬­¬¬­¬¬­¬¬­¬­¬¬­¬­¬­¬¬­¬¬­¬­¬­11111¿1111¿¿¿¿¿¿®®®®®®®®®®­®®­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®­¬­­¬¬¬¬¬¬¬¬­¬¬¬¬­­­­­­¬­¬­¬¬­¬¬­¬¬­¬¬­®­­­­­­­­­¬­¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬­­¬¬¬­¬¬¬¬­¬¬­®­­®¬¬­­¬¬­­­­¬¬¬¬¬¬««««««««««¬«¬¬«¬¬¬¬­¬¬¬¬¬««««««««««««««««««««««««««««««¬¬¬¬¬­­¬­¬¬¬¬¬­¬­¬­¬¬­­¬¬­­¬¬­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬­¬­­¬¬111111¿111¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®­®®®®­®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­¬®¬­¬¬­¬¬­¬¬­¬¬¬¬¬­­­­¬¬­­­­­­­¬¬­¬¬­¬¬¬¬­­­­¬¬¬­¬®­­¬¬¬¬¬¬¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­®®®­¬­¬¬¬¬¬¬¬­­­¬¬««««««««««««««¬¬¬­­¬¬¬¬­¬¬¬¬««««««««««««««««««««««««««««««««««««««««¬«¬¬­¬¬¬¬¬­­­­­­­­¬¬­¬­¬­¬¬¬¬­¬¬¬­­¬¬¬¬­¬¬¬¬¬­¬¬­¿11111¿¿1¿¿111®®®®®®®®­®­®®®­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬®­¬­¬¬¬¬¬¬¬¬¬­¬¬¬­­­­¬¬¬¬­¬¬­¬¬¬¬­­®®®­­­­­­¬¬­­­­­­¬¬¬¬¬­¬¬­¬­¬­¬¬¬­­­¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬®®®®®®®­­­¬¬­¬¬­¬¬­¬¬««««««««««­«¬«¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««¬­¬­¬¬­­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬­­¬­¬­¬­¬¬¬¬¬¬­¬¬¬­¬­¬¬¬11111¿¿¿¿¿¿111¿®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­­®­­¬­­¬¬­¬­¬¬­¬¬¬­­¬­®­­¬¬­¬­¬¬¬¬­¬­­®®®­­¬­¬­¬­¬­¬­­¬­¬­¬­¬¬¬¬¬¬­¬¬­¬¬­¬­­­¬­¬­¬¬­¬¬­¬­¬­¬¬¬¬¬­¬­®®®®®®®®¬¬­¬¬­¬­¬­¬¬¬««««««««¬¬«««¬¬­¬¬¬¬««««««««««««««««««««««««««««««««¬¬¬¬­¬­¬¬­¬¬­¬¬­¬¬¬­¬­­¬¬¬­­¬¬¬¬¬¬¬¬­¬¬­¬­­¬­¬­¬­¬¬­¬¬11111¿1¿¿1111¿¿®®®®®®®®®®®®®®®®®®­®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬¬¬­¬­­¬­¬­¬­­­­®­¬®­¬¬­¬¬­¬­¬¬¬­®­®®­­¬­¬¬¬­¬­­¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬¬­­®®®®¬¬¬­¬¬¬¬¬¬««««««««««­«¬¬¬¬¬¬¬¬­¬««««««««««««««««««««««««««¬¬¬­­­¬¬­¬­¬¬¬­­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬¬­­¬­­¬¬¬­111¿1¿¿1¿11¿¿¿¿¿®®®®®®®®®®®­®®®®­­®­®­­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­¬¬­¬¬­­­­¬­¬®­¬¬¬¬¬¬¬­®®­­­¬­­¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬­¬­¬­¬¬¬¬­­¬­¬¬¬¬¬­­¬¬¬¬¬­¬¬­¬­­­­­¬¬¬¬¬¬«««««««««««««««««««¬¬¬¬¬¬¬¬­«««««««««««««««««««««««««««««««««««««¬­®®¬­­¬¬­¬¬¬¬¬¬¬­¬¬­¬¬­­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬­¬111¿1¿¿¿¿¿¿®®®®®®®®®®­®®®®­®®®­®®®®®®®­®­®®®®®®®®®®®®®®®®®®®®®®¬®­­­­­­­¬¬¬­¬¬¬­­¬¬­­­­¬­­­¬­¬¬­¬¬­®®­­¬­­¬­¬¬¬¬­­¬¬¬¬­¬¬­¬®®¬­¬¬­­¬­¬¬¬¬¬­¬¬¬­¬¬¬­¬¬­¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬¬««««««««««¬««¬¬¬¬¬¬­¬¬¬¬­««««««««««««««««««««««««««««««««««««¬®¬¬¬¬­¬¬­¬­¬¬¬¬¬­­­¬­¬¬­¬­¬¬­¬¬¬­­­¬¬­¬¬­­¬¬¬¬­¬¬­¬¬¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­®®­­­­¬­­­­®­­­­­­­¬¬¬­¬¬¬¬¬¬¬­¬­­­®®®®­­­­¬¬­¬¬¬¬¬­¬¬¬¬­¬­¬­­¬­­¬­¬­­­­¬­¬­¬¬¬­¬««­­¬¬­­¬¬¬¬¬¬­­¬¬««««««««««««««««««««««««««««««¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬­­­¬­¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬­­¿¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®®­¬­­­¬¬­­®®®­®¬¬¬¬¬¬¬¬­¬­¬¬­¬­¬­­­­®­®®­¬¬­­¬¬­¬¬­¬¬¬­¬­¬­¬¬­¬¬­¬¬­¬­¬­­­®®¬­¬­¬¬­¬¬­¬¬¬¬¬«­¬­¬¬¬¬¬­¬¬­¬¬¬­¬¬¬«««««««««««««««««««««¬­®¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­­¬­­­¬¬¬¬¬¬­¬­­¬¬­­¬¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­¬¬¬­­­¬­­­®®­¬¬®¬­­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬­®­®®®®®­¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬­¬¬­­­­¬­­­­­­­¬¬­­­­¬¬¬¬¬¬¬¬­¬¬­¬­¬­¬¬­­¬¬­¬¬¬¬««««««««««««««««««¬«­­­­­¬¬¬¬¬¬­¬¬¬¬­¬¬¬­­¬­¬¬¬¬¬­¬­­¬¬¬­¬¬¬¬­­­­¬¬¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­¬­®®­¬­­­¬¬­¬­¬¬¬­¬¬¬¬­¬¬¬¬­­­­®®­®¬¬¬¬­¬¬¬¬­­¬¬­¬­¬¬­¬¬­¬¬­­­­­­­­¬¬¬¬¬¬­¬­­­¬««¬¬¬­¬¬­¬¬¬­¬­­¬¬¬¬««¬«««««¬««««««««««¬¬¬­¬¬­¬¬¬¬¬¬­¬­¬¬­¬¬¬­¬­¬¬¬¬¬­¬¬­¬¬­¬­­¬­¬¬­­­­¬¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­­®®®®­¬­­­¬­¬­¬­¬¬¬¬¬¬­­­­­­®®­­®®¬¬­­¬­¬¬­¬­­­¬¬¬­¬¬¬¬¬¬¬­­­­¬­¬¬­­­­¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­¬­¬¬­¬«««««««««««««««««««¬­­¬¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬­¬­­­­¬­¬¬­¬¬¬­¿¿¿®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­¬®¬¬¬­¬¬­¬­¬­¬¬¬¬­­¬­­­®­®­­¬­¬¬­¬¬­¬¬­¬¬¬¬®­­¬­¬­¬¬­­­­­¬¬­­­­¬¬¬­¬¬¬¬¬¬¬¬«¬¬¬¬­¬¬¬¬­¬­¬­­¬«««««««««««««««««­««­¬­­¬­­­¬­¬¬­­¬¬¬¬¬¬¬­¬­­¬­¬¬­¬­¬­¬¬­¬¬­­¬¬¬¬¬­¿¿®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­®®®¬­¬¬¬­¬¬¬¬¬­­¬¬¬­¬¬­­®­­­­®®®®®®®®¬¬¬¬­¬¬­¬¬®­­¬¬¬­­­­­¬­¬¬­¬­¬¬¬¬¬¬¬­¬­¬¬«¬¬¬¬¬¬¬¬¬¬¬¬­¬¬««««««««««««««««««««««¬­¬¬¬¬¬­¬­¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬­¬¬¬¬­¬¬­­­­­­¬¬¬¿®®®®®®®®¿®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®­®®®­­­­­­­­®®­­­­­¬¬¬¬¬­¬­¬¬­®­­­­­®®®®®®®®®®®¬¬¬¬­¬­¬¬­¬­¬¬­­¬­¬¬­­­­¬­¬¬­­­¬­¬¬¬­¬¬­¬¬­¬¬¬¬¬«¬¬¬¬¬¬¬¬­¬¬­¬­¬¬¬­­«««««««««««««««««««¬­¬¬­­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬­¬­­¬¬¬¬¬­¬¬¬­­¬¬­¬­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­¬­­­®®­®­­­­­­­¬¬¬­­­­­­­®®®®®®®­®®®­¬¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­¬­¬¬­¬¬¬¬­­­¬­¬¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­­­­®®®¬­¬­­¬¬¬«««««««««««««««««««««¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬¬¬¬¬­¬­­­¬­¬­¬¬®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®®®­­­­­­¬­­­­®®­¬­¬¬¬¬¬¬­¬¬­¬­­®®®®®®®®®®®®®®­­­¬­¬¬­¬¬¬¬¬¬­­¬­¬¬¬¬¬­¬­­­­¬¬¬¬­¬­¬¬¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬­¬¬¬­¬­¬­­¬¬­¬­­­¬««««««««««««««««««««««¬¬¬­¬­­­­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­­¬¬­¬¬¬¬¬¬¬­­­­¬¬­®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­¬­­­®­­­¬­¬¬¬­­­­­­­®®®®®®­®­®¬­¬­¬¬¬­­­¬¬¬¬¬¬­­­­­­­­­­¬¬¬¬¬¬­­­¬­¬¬¬¬¬¬¬¬­¬­¬¬­¬­¬­¬­¬¬®­¬­¬­­­««««««¬«««««««««««««¬®­«¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­­­­­­­­­­­­¬®¬¬­¬¬¬­­­­­®®®®®®®®®®®®¬­¬¬­¬¬­®­¬­¬­­¬­¬¬¬­¬­­­®®®®­­¬¬­­¬¬­¬¬¬­¬¬¬¬¬¬¬­­«¬­­¬­¬­¬­­¬¬¬­­¬«««««««««««««¬¬«­¬­­­¬¬­¬¬¬­­¬¬­¬­¬¬­¬¬¬­­­­¬­­¬­­¬¬¬­­­¬¬­¬¬®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­­­®®®®­­¬¬¬®®­­¬¬¬¬¬¬­­­­®®®®®®®®®®®®®¬¬¬­¬­®¬­¬¬®®¬­­¬­­­¬­­­®¬­­¬­­­­¬¬­¬¬¬¬¬¬¬¬¬«¬¬¬­­­¬¬­¬¬¬¬¬­­¬«««««««««««««««««¬¬¬¬«¬¬­­­­¬¬¬¬­¬¬¬¬­¬¬­­­¬¬­¬¬­¬­¬¬­¬¬¬­­¬¬¬­­­­­¬¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­®­¬¬¬­­­¬¬¬¬¬¬¬­­­­­®®®®®®®®®®®­®¬­¬¬­­¬¬­¬¬­­¬¬¬¬­¬®­­­®®¬­¬¬­­¬¬­­­®¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬­¬¬­¬¬­­¬­­¬¬­­¬¬««««««««««««¬¬««¬­¬­­­­­­¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬­­¬¬¬­­®­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­®®­­­­­¬¬¬¬­¬¬¬¬¬¬­­®®®®®®­®®®­¬¬­¬¬®­¬¬­®­¬­¬­­¬­¬­®­­­­®®­¬­¬¬¬­¬®­­¬¬­¬¬¬¬¬¬¬«¬¬¬­¬­­­¬¬¬­¬¬¬­¬­¬¬¬««««¬««««««««««¬¬¬¬¬­­­¬¬­¬¬­¬­¬¬¬¬­¬­¬­¬¬¬­¬¬­¬¬­¬¬­¬¬­¬­­­­¬¬®­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬­­­­¬­­­­®­­­­­­­­¬¬­­­¬¬¬¬­¬¬­­®®®®­¬¬¬­­¬¬¬­­¬¬¬­¬¬¬¬¬­¬¬­­­¬®®­¬¬­¬¬¬­¬¬­¬­­¬¬¬¬¬¬¬«­­­­¬¬¬­­­­¬¬­¬¬¬¬¬««««««««¬««««««««««««¬¬«¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬­¬¬­¬¬­¬­­¬¬­¬­¬¬­¬¬­¬¬­¬¬¬­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­¬­­­­­­­­­¬¬­¬­¬¬­­­­­¬­¬¬¬­¬­­¬¬¬­¬¬¬¬¬¬¬­¬¬¬­­­®¬­¬­¬¬¬¬­­¬­­¬­¬¬¬­¬¬¬¬¬¬­­¬­­¬­¬­­¬®®®®­­­­®®®¬­¬¬­­­¬­¬­¬­¬¬¬¬­¬¬¬¬¬¬¬«¬­¬¬¬¬¬­¬­¬­¬¬¬¬­¬­¬¬«««««««¬­¬¬¬«««¬¬¬¬­¬­¬¬¬¬­¬¬¬­¬¬¬¬¬­¬¬¬¬­­­¬¬¬¬¬¬­¬­­¬­®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­¬­¬­­¬­­¬¬¬¬­¬¬­­¬¬­¬¬¬­¬¬­¬­­­­¬¬­¬­¬¬­¬¬¬­¬­¬¬¬­¬­­¬¬¬¬¬­­­¬­¬¬­®¬¬­­¬¬¬¬­­­­¬¬­¬¬®®®®®®®®®­¬­­­¬­­­¬¬­¬¬¬¬­¬¬¬¬­¬­­¬¬¬­­¬­¬¬«««««««««««««««««¬«¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬­¬­®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­¬­­­­­¬­¬¬­¬­¬­­¬¬­­­¬­­­¬¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬­­­­­­¬¬¬­¬­¬¬­¬¬­­­¬¬¬¬­¬­¬®®®®®®®®­®®®¬¬¬¬­¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬®­­­¬­¬¬­¬«««««««««««««««¬¬¬¬¬­­­¬¬¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­­¬¬­¬®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­­¬­¬­¬¬­¬­¬­¬­­­­­­­­­¬¬­­¬¬­¬­¬¬¬¬¬¬­­¬­­¬­¬¬­¬¬­­­¬­®­¬¬¬¬­­­¬­¬­¬­¬¬¬¬­¬¬­¬¬®®®®®­®®®­­­¬¬¬¬­¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬­¬®®®¬¬­­¬¬«««««««¬«««««««««­¬¬­­­¬¬¬¬­­¬¬¬­¬¬¬­¬¬¬¬­¬¬­®¬¬®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­®­­­­­­­¬­­­­¬­­­¬­¬­­­­¬­­­¬­¬¬¬­­­¬­¬¬¬­¬¬¬¬­¬¬¬¬­¬­¬­¬¬¬­­¬¬¬¬¬­¬­­­®®®®®®®®®¬­­­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬­­­­¬¬­¬¬««««««««¬«««««««««««««««¬¬­­¬¬­­¬¬¬¬¬¬­¬¬¬¬­­¬¬¬¬­­­­®¬­­­®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬­­­­­­­­¬¬­¬­¬¬­¬­¬­­­­¬¬­­¬¬¬¬¬¬¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬­¬­­¬¬­¬­¬­¬­¬¬­¬¬¬¬­¬¬­­­­®®®®®®­­¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬¬®­¬®­­­¬¬¬¬««««««««««¬«««««««««¬««««¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­­­¬¬¬­­®®¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­¬¬¬¬¬¬­¬¬¬­­­­­­¬­¬­¬¬¬¬­¬¬¬¬¬­¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬¬¬­­¬¬­¬¬­¬¬¬¬­­­®­­­®®®®¬­¬®¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬­­­¬¬®­¬¬¬««««««««¬««««««««««««««¬­¬­­¬­¬¬­­¬¬¬¬¬¬¬­¬¬¬­­­¬­­®­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬­­­¬¬­­¬¬­­­­¬­¬¬­­­¬¬­¬¬­¬­¬­¬¬­¬­­¬­¬¬­­¬­¬¬­¬­¬¬­¬¬­­¬¬¬¬­­¬¬­¬­¬­¬¬­­®­®®®®®®®­­­¬¬­¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­­¬­­¬¬¬««««««««««««««««««««««««««««¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­­­­­­¬­­­­­­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­­­­­­­­­­¬¬­¬¬¬¬¬­­¬¬­­­­¬¬¬­­¬¬­¬¬­¬¬¬­­¬­¬¬¬¬­­­¬¬­¬¬­¬¬¬¬­­¬¬¬­¬­¬¬­­¬¬­¬¬¬¬­¬¬¬¬­­®®®®®®®¬­¬¬­­­¬¬¬­¬¬¬­¬­¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬««««««««««««««¬¬¬¬­®­¬¬­¬­¬¬¬¬­¬¬­­¬­¬¬­­­­­­­¬­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬­­­­­­¬­¬¬¬­¬­¬­­¬¬­­­­¬­¬­®­¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬¬­¬­¬¬­¬­¬¬­¬¬­¬¬­¬¬­¬­­­®®®®®®®¬¬¬­¬­­¬­¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬­­¬¬­¬¬­¬¬¬¬«««««««««««««««««««¬¬¬¬¬®­¬­¬­¬¬¬¬­­¬¬¬¬¬­­¬­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿¿¿1¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­­®®®­­­®­­­­¬¬¬¬¬­¬­­­­¬­­­¬¬­­¬­¬­­­­¬­¬¬¬¬¬­­¬¬­¬­¬¬­¬¬¬¬­­¬¬¬­¬¬¬­¬­­¬­¬­¬¬­¬¬­¬¬¬¬­®®®®®®¬¬­¬­­¬­­­­¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬­­­¬¬­¬¬­­¬­«««««¬««««««««««««««««««««««««««¬¬¬­­¬­¬¬¬¬¬¬¬¬¬¬­­¬¬¬­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿1¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­­­®­¬¬­¬­¬­­­¬­­­¬­¬¬­¬­¬¬¬­¬¬¬¬­¬¬¬­­¬¬¬¬¬­¬­¬¬­¬¬¬¬¬­­¬¬­¬¬¬¬­¬­¬¬­­­¬­®®®®­­¬­®®®®¬­¬¬­­¬¬¬­¬¬¬¬¬­¬¬­¬­¬­¬¬¬¬­¬¬­¬­­­­­¬¬¬¬«««««««««««««««««««««««««¬¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­®­­­­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬­­­­¬¬­­­­¬¬¬¬¬¬¬¬­­­­­¬­­­­­­¬¬­¬­¬¬¬¬¬­­¬¬®­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬¬­¬¬­¬­­­®®®®­­¬­­®®®¬­¬¬¬­­­¬­¬¬­¬¬­¬¬¬­­¬¬­¬¬¬­¬¬­¬¬­­¬«««««¬¬¬««««««««««««««««««¬¬­¬­­­­­¬­¬¬¬¬¬¬¬¬¬¬¬­¬­­­¬­­¬­¬­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­®­­­¬­­­¬¬¬¬­­¬¬­¬¬­­­­¬¬­­­¬­¬¬¬­¬¬¬¬¬¬­¬­¬­¬­­¬¬­¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬­¬¬­¬¬­¬­¬­®®¬¬­­®®­­­­¬¬¬­­¬­¬¬¬­¬­¬¬­­¬­¬­¬­¬­¬¬¬¬¬­¬­¬¬­¬¬¬¬««««««¬«««¬««««««««««««««««¬¬¬­­¬¬¬¬¬¬¬­¬¬¬¬¬­­­­­­¬­­­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®¿1¿¿¿¿¿¿¿1®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®¬¬­­®­­­­¬­­­­¬¬­¬¬­­¬¬­­­¬­­­­¬­­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­­­­­¬¬­¬¬¬­¬­¬­¬­¬¬¬­¬­¬¬¬¬­¬­¬¬­¬­¬­®®®®®®­­­¬¬­­®®­­­¬­¬­¬­¬¬¬¬¬­¬¬­¬¬¬¬¬­¬­­­¬¬¬­¬­¬¬¬««¬«««««««««««««««««««««¬¬­­­­­¬¬¬¬¬­­¬¬¬­­¬¬­¬¬­­­­­­¬¬­­­­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­­­­­­­­­­¬­­¬¬¬¬¬¬­­­­¬¬­¬¬¬¬¬¬­¬¬­¬¬¬­­¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬¬¬¬¬¬­¬¬¬­®¬­­¬¬­¬¬­¬¬­¬¬­¬®®®®®­¬¬¬¬­®¬¬¬­¬¬¬­­¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬­¬­¬«««««««««««««««««««««¬¬¬­­¬¬¬­¬¬¬¬¬­¬¬¬¬¬­­¬¬­­­­­­­¬­¬­¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬­¬¬¬¬¬¬­­­¬­¬®®®­¬­¬¬¬¬¬¬¬¬­­¬­¬¬¬¬¬¬­¬­­¬­¬¬­¬¬­¬¬­¬¬­¬¬¬­¬¬¬®®®®­¬®¬¬­¬­¬¬®¬­­­­¬¬¬­¬¬¬¬¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬««««««««««««««««««¬¬­­¬­¬¬¬¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬­­¬¬­­­­­­­­­­­­­¬¬­­®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®­­­­­­­­­­¬¬­¬¬¬­¬¬­¬­­­¬­­¬­­­¬¬¬¬¬¬­¬­¬­­¬¬¬­­¬¬¬­­¬¬¬¬¬¬­¬¬­¬¬­­­¬¬¬­­®¬­­­¬¬¬­­­¬­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««¬¬¬¬¬­­¬¬¬­¬¬­¬­¬­¬¬¬¬­¬­¬­¬­­­¬­­­­¬­¬¬­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­¬­¬­­¬­¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬­­­¬­­­­¬¬¬¬­­¬­¬¬­¬¬­¬¬­¬­­­­­­¬­®­¬­¬¬­¬­¬­­­­¬®­­¬¬­­­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬®¬¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬«««««««««««««««¬¬¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬­¬¬¬­­¬¬¬­­­­­­­­¬¬­¬­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬¬­¬¬­¬­¬¬­­¬­­¬­¬¬¬¬¬¬¬­¬­­¬¬¬­¬¬­­¬­­¬­­­¬­¬¬­¬¬­¬¬¬¬¬­­¬­­­¬­®­­¬­¬¬¬­­­­­¬®®­­¬­¬¬­¬¬­­­¬­¬­¬¬­¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬­­¬­­¬¬­¬¬­­¬¬­­¬¬¬¬¬¬¬««««««««««««««««««¬¬¬­­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­­­¬¬¬­­­­­­­­¬­¬­­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­¬­­­¬­¬­­¬­¬¬­­¬¬­¬¬¬¬¬¬¬­¬¬­­¬¬¬¬¬¬­­¬­¬­­¬­­¬¬­¬¬­¬¬¬¬­¬¬­­­¬¬­¬¬®­®®­­­¬¬­¬¬­¬­®­¬­¬¬¬¬­¬¬¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­­­¬¬¬¬«««««««««««««««««««¬¬¬¬¬­­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­­­­­­­­­­­­­­®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­­­­­­¬­­­¬¬­¬¬¬­­¬¬­­¬¬¬¬¬¬¬­¬­¬¬­¬¬¬¬¬­¬¬¬­¬­¬­¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬¬­®­¬­­­¬­¬¬­¬¬¬¬­­¬¬¬­­­¬¬¬­¬¬¬­¬¬­­¬¬­¬¬­¬¬¬¬­¬¬¬­­¬¬¬¬¬­¬¬­¬¬­¬««««««««««««««««««««¬¬­­¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬­­­¬¬­­­­­®­­®®­­­­¬­­¬¬¬¬­­®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®­­­­­­¬­­¬­¬¬­­¬¬­­¬­¬¬¬¬¬­­¬¬­¬¬­¬¬¬¬­¬¬­¬¬­¬­¬¬­­¬­¬¬­¬­¬­¬¬­¬­¬¬­­­­¬­­¬­¬­­­¬­¬­¬¬­­­®­­¬¬­­¬­¬­­­¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬¬­­¬¬««««««««««««««««««¬­¬¬¬­¬­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­¬­­­¬­­­­®­­­¬¬¬­¬­­®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬­¬­¬­¬­¬­¬­¬¬­­­¬­¬¬¬¬¬­¬­­¬¬¬­¬­¬­¬­­­¬¬­¬­¬¬­­¬­¬­¬¬­¬­¬­­­­­¬¬¬¬¬­­­¬­¬­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬­¬­¬¬¬«««««««««««««««««««««««««¬¬­­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬­­­­­¬­¬¬­­­­­¬®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­­­­­­­­¬¬­¬­¬­¬¬¬¬¬­¬¬­­­¬¬¬¬¬¬¬­­¬¬¬¬¬¬­¬­­­¬¬¬­¬­­­­¬¬­¬¬­¬¬­¬­¬¬­­­­­­¬­¬¬¬­®­­¬¬­¬­¬¬­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬­¬¬­¬¬¬¬¬¬¬««««««««««««««««¬¬­­¬­¬¬¬­¬­­­¬¬¬¬¬­¬­­­­­­­­­­­­­­­­­­®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­¬­¬¬­­­¬¬¬¬­¬­¬¬¬¬¬¬­®­¬­¬¬¬¬¬¬¬¬¬­­¬­­­¬¬­­¬­¬­¬­­­­­­¬­¬¬¬­­¬¬¬­­¬­­­­¬­¬¬­­­­­­¬¬­¬¬¬¬¬¬¬¬¬­­¬¬­¬¬¬­­­­­¬¬­¬­¬¬¬¬¬«««««««««««««««««««««¬¬­¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬­­¬¬­¬­­­­­­­¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­­¬¬­¬¬­¬¬­­¬­¬¬­¬¬¬¬­­¬¬¬¬¬¬¬­­¬¬­¬­¬­­¬­¬¬¬¬¬­­¬¬­­­¬®­­­­¬¬­¬­­­¬¬¬¬¬¬­¬¬­¬¬¬­¬¬­­­¬¬¬¬­¬¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬­¬¬¬¬«¬¬«««««««««««««««««¬¬­­­¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬­­­­­­­­¬¬¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬¬­¬¬­¬¬­¬¬­­­¬¬¬­­¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­­¬¬¬­­¬¬­¬­¬¬¬­¬®­¬¬­­­­­­­­¬¬­®­¬­­­­¬­¬¬­­¬­¬­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬«««««««««««««««««¬¬¬¬­¬­¬¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­¬­®­­®®­­­­­­®®®®®®®®®®®®®®­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­¬­¬­­¬¬¬¬­­­¬¬­¬­­­­¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­¬­¬¬­¬­¬­¬¬­®­¬­­­­¬­­­¬¬­­­­­­­¬­­¬¬­­¬­¬­¬¬­­­¬­¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬««««««««««««««««««««¬¬­¬­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬¬­­­®¬¬¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬­¬¬­¬¬¬¬­¬¬­¬­¬¬­­­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­­­­¬¬­¬¬¬­¬­­­¬­­­­­¬¬­¬¬¬­¬¬¬¬­¬­­¬¬¬­­¬­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬­­¬¬¬¬¬¬­­­¬¬¬¬¬¬¬««««««««««««««««««««¬¬­­¬­¬¬¬­¬¬­¬¬¬¬¬¬¬­¬¬¬­­¬­­¬­­­­®®®­­­¬®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®­­¬­¬­¬­¬¬­¬¬¬¬­¬¬­¬­¬¬­­­¬¬¬¬­¬­­­¬¬¬­¬¬¬­­¬­¬¬¬¬­¬¬­­¬­¬¬­®­­­­­­­­­¬¬­¬¬­¬¬­¬­­­­­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­­¬­¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««¬­¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬­­¬­­­­­­®®­­®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­¬­¬¬¬­¬¬­¬­¬­¬­¬­¬­­­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬­¬­¬­­­­­­¬¬­¬¬¬­­­­­¬¬­­­­¬­¬¬­­­­¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬­­¬¬­¬¬¬¬¬¬¬­¬­¬­­¬¬¬¬¬¬¬«««««««««««««««««««««¬¬¬­¬¬¬¬¬¬¬­­­¬¬­¬­­­¬¬¬­­­­­­­­­®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­­¬­¬¬­¬¬­¬¬¬¬­¬­­­¬­­¬¬¬¬­­¬¬­¬¬¬¬¬­­¬­¬¬­­¬­¬¬­¬¬¬­­¬­­®­­­­­­­­­­®­­­­®­¬­­¬¬­­­­¬­­­­¬¬¬¬¬­­¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««¬¬¬¬­¬¬­¬­­­­¬¬¬¬­¬­­¬®­®®­®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬­¬¬­¬­¬¬­¬¬­¬­­­­¬­¬­­¬­¬¬­¬¬¬¬¬­¬­­­¬¬¬­¬¬­¬­­­­­­­­­­­­­­­¬­­¬­­­¬­­¬­­­¬¬­­­­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬­¬¬­¬­­¬¬¬¬¬¬¬¬­¬­­¬­¬¬­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬­¬««««««««««««««««¬¬­­­¬¬­­­­­­­­­¬­­­­­¬­¬­­®®®®®®®®®®®®®­­­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®­­¬­­­­¬¬¬¬­¬¬­¬¬­­¬­­­¬­¬¬¬¬­­¬­¬¬¬¬­¬¬¬¬¬­­­­­¬­­¬­­­®­®­­­®­­­­­­­­­­­­­®®¬­¬­¬¬­­®­­­¬­¬¬¬­­­¬­¬¬¬­­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬­¬¬¬­­¬¬¬¬­¬¬¬¬¬¬«««««««««««««««««¬¬¬­¬­¬¬­¬­­­­¬¬­¬­¬­¬¬­­­®®­®®®®®®®®®®®®­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬­¬¬­¬¬­¬­¬¬¬¬¬­¬­¬­¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­­­®®­­®®­­­­­­­­­¬­­®­¬­¬­¬¬­­¬¬­¬­­¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­­¬¬¬­¬¬­¬­­­¬¬¬­¬¬­¬¬­­¬¬¬¬­­­¬¬¬¬««««««««««««««¬¬­­¬­¬¬­­­­­­­­¬¬­­­­¬­®®®®®®®®®®®®®­®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬¬­¬­¬¬­¬¬¬­¬­¬¬¬­¬­­¬¬¬¬¬¬­­¬¬¬¬¬¬­¬¬¬­­¬­¬­¬­­­®­­®®®®­­­­­­­­­­­­¬­­®®¬­¬¬­¬®®®®®­­­­¬¬­¬¬¬¬¬¬­­¬¬­¬­­¬¬­­¬­¬¬¬­¬¬¬¬¬¬­­¬¬¬­¬¬¬­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬«««««««««««««««¬­­­¬¬­¬­­­­¬­­­¬­­­­­­­­­­­­­®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®­­¬­¬¬­¬¬­¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­­¬¬­­­­®®®­­­­­­¬­­®¬­¬¬­®­¬­¬­¬¬­­¬­¬¬¬¬¬­­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­­¬­¬­­¬­­­¬¬¬¬­­­­¬¬¬­­¬¬¬­¬««««««««««««««««¬­¬­¬¬­¬¬¬¬­­­­­­­­­­­®¬­­­­®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®­­¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬¬­­­¬­­­¬­­­­¬¬¬¬¬¬¬¬¬¬­¬­¬­­­¬¬¬­®­­­­­­­­­­­­­­­®®®®­¬¬¬¬­¬¬­¬¬¬¬­¬¬­­¬¬­­¬¬¬¬¬­¬­­¬¬¬­­¬­­¬¬¬¬­¬¬­¬¬­¬­¬­­¬¬¬¬¬¬¬­¬¬¬«««««««««««¬­­¬¬¬¬­¬­­­¬¬¬¬¬­­­­­­­®®®­­­®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®¬­­¬¬¬­­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬¬¬­¬­­¬¬¬¬¬¬­¬­­­¬­¬¬¬­­­®­­­­­­®­­­­­­¬¬­¬¬­¬­­­®­¬­­¬­¬¬¬­¬¬­­­­¬¬­¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬­­­¬¬¬¬­¬¬¬¬¬««««««««««««¬­¬¬¬®¬¬¬¬­­­­­¬¬¬¬­­¬­­®®®­­®®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®¬­¬¬­¬¬­¬¬¬¬¬­¬¬­¬¬­¬­¬­¬­¬¬­­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬­­­¬­­­­­­­­®­­­¬­­­­­¬¬¬­®®­­­¬¬­¬¬¬¬¬­¬­¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬­¬¬­¬¬­¬­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬«««««««««««««¬¬­¬­­­¬­¬¬­­­­­¬­­­­­®®®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­­¬¬­¬¬­¬¬­¬¬­¬¬­­¬¬­¬¬¬­­¬¬­­¬­¬¬¬­¬­­¬­­¬¬¬¬¬¬­­­­­­®®­¬­­®­­¬­­¬­­­­­®®®­¬¬­¬¬¬¬­¬­¬­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬­¬­¬­­¬¬­¬¬¬­¬¬­¬¬¬¬¬¬¬¬­««««««««««««««¬¬¬¬­¬¬®¬¬¬¬­­¬­­®­­­­­­®®®®®®®®®®®®®®®®®®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­¬¬­­¬¬­­¬¬­¬¬¬­­­¬­¬­­¬¬­¬¬¬­­¬¬­­­­¬­­­­­­­­®­¬­®¬¬¬­¬­¬­­­®®®­­­¬¬­¬­¬¬­¬¬¬¬¬¬­¬­­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬­­¬¬­¬¬¬­¬­¬­¬­¬¬¬¬­¬­­¬¬­­¬¬¬¬¬¬«««««««««««««¬¬­¬¬­¬­­¬¬­¬¬­¬¬­¬¬­®­®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬­­¬¬­¬­¬¬­¬¬¬­¬¬­­¬­¬­­­¬¬¬¬­­¬¬­­¬¬­­¬­¬­®­¬­®­¬¬¬¬­¬¬¬¬­­­­®®­­­­­¬¬­­¬­­¬­¬¬­¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬­­¬¬¬¬¬­¬¬­¬­­¬¬¬¬¬­¬¬­¬¬¬¬¬¬««««««««««¬¬­¬­­¬®¬¬­¬­­­­­¬¬¬­­­­­­®®®®®®®®®®®®®­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­¬¬­¬¬­­¬­¬­­­­­¬­­¬¬­¬­¬¬¬­¬­¬¬­¬¬¬¬¬­¬­¬¬¬¬­­®®®®®®®®®­®®¬­¬­­­¬­­¬­¬¬­­­­®®®®­­¬¬­¬¬­­¬¬¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬­¬­¬¬­¬¬¬­¬¬¬¬¬­­­¬¬¬­­¬¬¬¬¬­¬¬¬«¬«««««««««««­­¬­¬­¬¬­­­¬¬­¬¬¬­­¬¬­®®®­®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­­¬­¬¬¬¬¬¬­¬­¬­¬­¬­­¬¬­­¬­­¬¬¬¬­¬¬¬¬¬­­­­­­¬­­­­®®®®®®®®®®®®­­­¬®¬®®®®®­¬­­­¬­­­­­®­­­­¬¬­­¬¬­¬¬¬­¬­­¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬­¬¬­¬¬¬¬­¬­¬­¬¬­¬­¬¬­¬­­¬¬¬­­­¬¬¬¬¬¬¬¬¬«¬«««««««««««­¬¬¬­­­¬­¬­­¬¬¬­¬­­­¬­­­­¬­®®®®®®®®®®®®®®®®­®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬­¬¬¬­¬­­¬¬­­¬­¬¬­¬­¬­¬­¬¬¬¬¬­­¬­¬¬­¬¬­¬­¬¬­­­®®®®®®®­®­¬®®­¬­­­­­­®®­­¬­¬¬­­­­­¬¬­­¬­­¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬««««««««««¬­¬¬­¬¬­¬­­­­¬­­¬¬­­­­®­®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬­¬­¬¬­¬­¬­¬¬­¬­¬¬¬¬¬­­­¬¬­¬¬¬¬¬¬­¬­¬­¬¬¬¬­¬¬­­­¬¬­­­®®®®®®®®®®®®®­­®­­­¬­­¬¬¬¬¬¬­¬­¬¬­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬¬¬¬¬­¬¬¬­¬¬­¬¬¬­­­¬­¬¬¬¬¬¬­­¬¬¬¬¬¬¬­¬«««««­­­­¬¬¬­­®®®®­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬¬¬­¬¬¬­¬¬¬­¬­­¬¬­­­¬¬¬­¬¬­­­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬­­¬­¬­¬­®®®®®®®®®®®®®®®®­®®­­­­­­­­¬­¬­¬¬­­­­­¬¬­­­­¬­­­¬¬¬¬­¬¬¬®¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬­¬¬­­­­¬­­­¬¬­¬¬¬­¬¬¬¬­­¬­¬­­­­¬¬¬««¬««¬­¬¬­¬¬­¬®¬­­®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬¬­¬¬­­¬­­¬­­­¬­­­­¬­­­¬­­¬­¬­¬¬¬­¬¬¬¬¬­¬¬­¬­­­­¬®®®®®®®®®®®®®®­­­®­­®®¬¬­­­­­­­¬­­¬¬¬¬¬¬¬¬­¬­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬¬¬¬­­¬­­­­­­­­¬­¬­¬¬­­¬­¬¬¬¬¬¬­¬¬¬¬¬«¬««««««¬¬¬­¬­¬¬®¬¬®®®®®®®®®­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­¬¬­­¬¬¬­¬­­¬¬¬¬­­¬¬¬­­­­­¬­¬¬­¬¬­­¬®®¬­¬¬­¬­¬¬­¬¬¬¬­¬¬®®®®®®®®®®®®®®­®®®®®®®­¬­­­­®­­¬­­­­­­¬¬¬­­¬¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬­¬­­­­­­­¬­­­¬­¬­¬­¬­¬¬¬¬¬­¬­¬¬¬¬««««««¬¬­¬¬¬¬®­®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­¬­¬¬¬¬­¬¬­¬­­¬¬­­¬­­­­­¬¬­¬­¬­­¬¬¬¬®®­¬¬­¬­¬¬¬­¬­¬¬­®®®®®®®®®®®®®®®®®®­­­­­­­­­®­­¬­­¬­­­­­¬¬­­­¬¬­¬­¬­¬­¬­­¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬­¬­­­­­­­­­­¬­¬¬­¬¬­­¬¬¬¬­¬¬­¬¬¬¬¬¬««¬­¬¬¬¬­­®­¬¬­®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬¬­¬¬­¬¬¬¬­­­¬­­­¬­­­­¬­¬­­®®®¬¬¬¬­¬¬¬­¬¬¬­¬®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬­­¬¬¬¬¬­­­¬¬¬­­¬¬¬­­¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬­¬­­¬­¬­¬¬­­­­­­­­¬¬­¬­¬¬­¬¬­¬¬¬¬­¬­¬­¬¬¬«««¬¬¬¬¬¬­­­­­­­®®­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬­­¬¬¬¬­¬­¬­¬¬­¬­¬¬¬­¬­¬¬­¬¬¬­¬¬­¬¬¬­¬¬¬¬­­¬¬­®®®®®®®®®®®®®®®®­®­¬¬­¬¬­­­¬¬¬¬­­­­­¬¬­­­¬­­¬¬­­¬¬¬¬­¬­¬¬¬¬¬¬­­­­­¬¬­¬¬­­­¬­­­­­¬­¬¬­¬¬¬­­¬¬¬¬¬¬­­¬¬¬¬¬¬««««¬¬¬­¬­­­­­®¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­­­­­¬¬­¬¬¬¬­¬­­¬¬¬­­­¬¬­¬­­¬¬¬­¬­¬­¬­¬¬­¬¬­¬¬­¬¬­­­¬¬¬­¬¬­¬­®®®®®®®®®®®®®®®¬­­­­­­­­­­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬­­­¬¬­¬­¬¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬­­­­­­­­¬­¬¬¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬­¬¬«««««¬¬­¬­¬­®¬­­¬­­­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬­­¬¬¬¬­¬­¬­­­­¬¬­¬¬¬­­¬­¬­¬¬­­¬¬­¬¬­¬¬¬­¬­¬¬¬¬­­¬¬­¬¬¬­¬®®®®®®®®®­®®¬¬­¬­­¬¬¬¬¬¬­¬­¬¬­­­­¬¬­¬¬­¬¬­¬­¬­­¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬¬­¬¬­¬¬­­¬­­­­­­¬­¬¬¬­¬¬­¬­­­¬¬¬¬¬­¬­¬¬«««¬¬¬¬¬¬¬­¬®¬­­­­­­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­­­¬­¬¬­¬¬­¬¬­¬¬¬¬­­­­¬­¬¬­­­¬¬­­¬¬­¬¬¬¬­¬¬­¬­¬¬¬­­¬¬®®®®®®®®®®®­®­­¬¬­­­­¬¬­­­¬¬¬¬¬­­¬¬¬­¬­­¬¬­¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬­¬¬­­¬­­¬­­­­¬­¬¬¬­¬­¬­¬­¬¬¬¬¬­¬¬¬¬«««««««¬¬¬¬­¬­­­­­­­­¬­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬­­¬¬­¬¬¬¬­¬¬­­¬­¬¬­­¬­­­­­­¬¬­¬­¬­¬¬­­¬¬¬¬¬¬­¬­¬­­¬¬¬¬¬®®®®®®®®®­­­®®­­­­­­­­­¬­¬¬­¬­­¬¬­­¬¬¬¬­¬¬­¬­¬¬­­¬¬¬¬¬¬¬­¬¬­¬¬­­¬¬¬¬¬­¬¬­­­¬¬­­¬­¬­­¬­¬¬¬¬­­¬¬¬¬¬¬¬¬«««««««««¬¬¬­¬¬¬¬­¬¬­¬¬¬­­®®®®­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬¬­¬­¬­¬­¬­¬¬¬¬­­­­¬¬¬¬­­¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬®®®®®®¬¬®®®®­­®­­­­­­­­­­­­¬¬­¬¬­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬­­¬¬¬­­­­¬­­­­¬¬¬­¬¬¬¬¬¬¬¬¬««««««««««¬­¬¬­­¬¬­¬­¬¬®­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­¬¬­¬¬­­­¬¬¬­­­­¬¬­­­­­­­¬­¬¬¬­¬­­¬¬­¬­¬¬­¬¬¬­¬¬®®®®®®®¬¬®®­­­¬­­­­­­­­¬¬­­­­­¬­­­­­¬¬¬¬­¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬­¬¬­­­­­­­­¬¬­­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬««««««««¬¬¬¬¬­¬­¬¬­¬¬­­¬­­­®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬­¬¬¬¬­¬¬¬­­¬¬¬­­­¬­­¬­¬¬­­¬­¬¬¬¬­¬¬­¬¬­¬¬¬­­­¬­¬¬®®®®®®¬¬®­­¬­­­­¬¬­­¬¬­¬­¬¬­­­¬­­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­­­­­¬¬­¬¬­¬­­­­­­­­­¬­­­¬¬­¬­¬­¬­¬««««¬¬¬­¬¬¬¬­¬¬¬¬¬­­¬¬­­­­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­®¬¬­¬¬­¬¬¬¬­¬­­¬¬­­¬­¬­­¬¬­­¬­¬¬®®®®®®®®®®­­®®®­­­­­­¬­­­¬­¬¬¬­­­¬­¬¬­¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬­¬¬­­­­­­­­­­­¬¬­­¬­¬¬­¬¬¬¬¬¬«««««««¬¬¬­¬­®¬¬­¬¬¬­­¬­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­®­­­¬¬­¬¬­¬­¬¬­¬¬¬­¬­¬¬­¬­¬¬¬¬¬­­¬­­­­­­¬¬¬­¬¬­¬¬­­¬®®®®®®®®®­­­®®®®­­­­­­­¬®­­­­­­­­­­­­­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬­¬¬­­­­­­­­­­­¬¬­¬¬­¬­­¬¬¬¬¬¬«««¬¬¬­­¬¬¬¬¬­¬­­¬¬¬¬®­¬¬­­­­­­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®¬¬­­¬­¬­¬¬¬¬­¬¬¬­¬¬­­­¬¬­¬­­¬­¬¬­¬¬¬­¬­­¬­¬¬­¬¬­­­­¬¬¬­®®®®®®®®®­­®­®­®®­¬­­¬­®®­¬­­­­¬¬­­¬­¬­­¬­­¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬­­¬¬­¬¬¬­¬¬¬¬­­­­­­­­¬¬­¬­¬­¬­¬¬¬¬¬¬«««««¬¬¬¬­¬¬­¬­®­¬­­¬­­¬­­­¬­­­­¬­­­®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­¬¬­¬¬¬¬­¬­­¬­¬­¬¬­­­¬¬¬­¬¬¬­­­­¬¬­¬¬¬¬¬­¬®®®®­­­­­­­®®­­­­­­­­­­­­­¬¬­¬¬­¬¬­­¬­­¬¬­­¬¬­¬­¬­¬¬­¬¬¬­¬¬¬¬¬¬¬­¬­­¬­¬­¬­­­¬¬­¬¬¬¬¬­¬¬¬¬¬­««¬¬¬­¬­¬¬­¬¬­¬¬¬¬­¬­­­¬¬¬­­­­­­­­®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬­¬¬¬¬­­¬­¬­¬­­¬¬¬­¬­¬­¬­­­¬­¬¬¬¬­¬­¬¬­¬¬­¬¬¬­¬®­­­­­¬­­­­­®­­­­­­®­­­­­­­¬¬­¬¬¬¬­¬¬­­¬¬­¬¬¬­­­¬¬¬­¬­¬¬¬¬­¬¬¬¬­¬­¬¬­­­­¬¬­­¬¬¬­­­­­¬¬¬¬¬­¬¬«««¬¬¬¬¬¬­¬¬­¬®¬¬¬¬¬¬¬¬¬¬­®­­®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬®­­¬¬¬¬¬¬¬¬¬¬¬­­¬­¬­¬¬­­­­¬¬­¬­¬­¬¬­¬­¬¬¬¬¬­¬­­­¬¬­¬®®®®®­­¬­­­®­­®­­­¬­­­­®­­­­­­­¬­¬­¬­­¬¬­¬­­­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬¬­¬­­­­¬¬­¬¬­­¬¬­¬¬­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬­­¬­­­­­¬¬­­­®­®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­¬¬¬¬¬¬¬¬¬¬¬®¬¬­¬¬¬­¬¬¬­¬¬­­­­¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬¬¬­®®®®®®­¬­­­®®­¬­¬­¬­­­­­¬­¬­­­­¬¬­¬¬­¬¬¬¬¬­­¬­¬¬¬¬­¬¬­¬¬¬¬¬­­­¬¬¬­¬¬¬­¬­¬¬­­­­­¬¬¬¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬­¬¬¬­¬­­¬®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­¬­­­­¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬­¬¬­¬­¬¬¬¬­¬¬¬¬­¬®®®®®®­­­­­­­¬¬¬­­®®®®­­­­­­­¬­®­­­­­¬­¬¬¬¬­­­¬­­¬¬¬­¬¬¬­­¬¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬««¬¬¬¬­¬¬­¬­¬­­­­­¬®®®®®®®¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬­­¬­­­­¬¬­­­­¬­¬­¬¬­¬­¬­¬¬¬¬­­­¬¬¬¬­¬¬­­¬¬¬¬¬¬­¬¬¬­®®®­­­­­¬­­­¬­®®®®®®­­­­­­­­­­­­­­­­¬¬­¬¬¬¬­­¬­¬¬¬­¬¬¬­­­¬¬­­¬­¬¬­¬¬¬­¬¬­¬¬¬¬­¬­¬¬­­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬­¬¬­¬­¬­¬­®­®­­®®®®®®®®®¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬­­¬¬¬­¬¬¬¬¬­­¬¬­¬­¬¬­¬­¬¬­¬­¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬­¬®®­®¬¬¬¬­®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬­¬­­­­¬­¬¬¬¬¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬­­¬¬­¬¬­­­¬¬­¬¬¬¬­­¬­­¬¬­¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬­¬­­¬¬¬­­®®®®®®¿1111®­¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬¬­¬­¬­­¬¬­¬¬­¬¬­¬¬¬¬¬¬­­¬¬­­¬­¬­­­¬­¬¬­¬¬¬¬­¬¬¬®®®®®­­­­­­¬¬¬¬®®­®®®®®­­­­­­­­­­­­­­­¬¬­¬¬­¬¬­­¬¬­¬­¬­¬¬¬¬­¬­¬¬¬¬¬¬­¬¬¬­¬¬­¬­¬¬¬­¬­¬¬­­¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬­­¬­®®®®®®®®®111111111111®¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­­­­¬¬¬­­­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­­¬¬­¬¬­­­¬­¬­¬¬­¬­¬­­®®®®®­­¬­¬¬­­­­®®®­¬­­®­­­­­­­®­­­¬¬¬¬¬­¬¬¬­­­­¬­¬¬­¬¬­¬­¬­­­¬­¬­¬­­­­¬¬¬­¬­¬¬­¬­¬¬¬¬­¬­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬­¬­®®®®®®®®®®®®®®®®®111111111¿1111111111111®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­¬­¬¬­¬­­¬¬­¬­¬¬­¬­­¬¬­¬­­¬­¬­­¬¬¬­­¬¬­­­¬­¬¬¬®®®®­­­­¬¬¬­­®®­­­­­­­­¬­­­­¬­¬¬­¬¬­¬­¬­­¬¬¬­­¬¬­¬¬¬¬­­¬­­¬¬­¬¬­¬¬­­¬­­¬­­¬­¬¬­¬­­¬¬­­¬­­¬¬¬¬¬¬¬­­¬«««¬¬¬¬¬¬¬­¬¬­­­¬¬¬­®1111111111111¿11¿111111111111111111111111111®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­¬¬¬­­¬­¬¬­¬¬­­­­¬­¬¬¬­­¬­¬­¬®­¬­¬­¬¬­¬¬¬­®®®­­­­­­­­¬¬¬­­¬­®®®®­­­­­­­­¬¬­­­¬¬¬¬¬¬­¬­¬­­­­­¬¬¬­¬¬­­¬¬­¬¬­¬¬¬¬­¬¬­­­¬¬­¬¬¬¬¬­¬­¬­­­­­­¬¬¬¬¬­¬¬­¬¬«¬¬¬¬¬¬¬¬­¬¬­­¬¬¬­11111111111111111111111111111111111111111111111111111®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬­¬­¬­­¬¬¬­¬­¬¬­¬¬­­­­®­­¬­¬­¬­¬­¬¬®¬¬­­¬¬¬¬­­¬¬­¬¬­­­­­­­­­­¬­­­®®®®®®­­­­¬­­­­­­­­­¬­¬¬­¬­¬­¬¬­­¬­¬¬­¬¬¬¬¬¬­¬­¬¬­¬¬¬¬­­­­¬¬¬¬­­­¬¬­¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­­¬¬­­­­­­­111111111111111111111111¿111111111111111111111®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­®¬­­­¬­¬­­¬¬­¬¬­¬¬¬¬¬¬¬¬­®­­­¬­¬¬­¬¬¬¬­¬­¬¬¬¬­­­¬­¬¬­¬®®®®­­­­®­­¬¬¬­¬®®­­¬­­­­­­¬¬­­­¬­¬­­­¬¬­¬­¬­­¬­¬¬¬¬¬­¬¬­¬¬¬­¬¬­­¬­­­­­¬­¬¬­­¬¬¬­­¬¬­¬¬¬­­¬¬¬­¬¬¬¬¬¬¬­¬¬«««¬¬¬­­¬¬­¬¬¬¬­¬¬­®11111111111111®®®¿¿11111111111111111111®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬¬­¬¬­¬¬­¬¬¬­¬­¬¬­¬®¬¬­¬¬¬­¬¬­¬¬¬¬¬­­­­¬¬¬¬¬¬¬®®®®­­­­­®­­­­¬¬¬­­¬­¬­­­­­­­­­­¬­¬¬­¬­¬­­¬­­¬¬¬­­¬¬­¬¬¬­­­­¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­¬¬­¬­¬­¬¬­¬¬­¬¬­­­­¬¬¬¬¬¬¬­¬¬¬¬¬¬«¬¬¬¬¬¬­¬­¬¬­­­­11111111111111®®®®®®®111¿1111111111111111111®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­¬­¬¬­­¬¬¬­¬¬­­­¬­¬­¬¬­­­­¬¬­¬­­¬¬­­®¬¬¬¬¬¬­®®®­­­­­¬­¬­®®®­­­­¬¬­­­­­­­­¬¬¬¬­¬¬­¬¬¬¬­¬­¬¬­¬¬­¬­¬­­¬¬­¬¬¬¬­¬­¬­¬­­­­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬«¬¬¬­¬­­­­¬­1111111111111®®®®®®11111111111111111111111111®®¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­¬¬¬¬¬¬­­­­­¬¬­¬¬­¬­¬­­­¬­­­­¬­¬­­®¬¬¬¬­­¬­®®®­­­­­¬­¬­¬­­­¬­­­­­¬­­­­­­¬­­¬­­¬¬­¬¬¬­­¬¬­­¬­¬­¬­¬¬­¬¬­¬­¬¬­­¬¬­­­­­¬­¬­­¬­¬¬­¬¬¬¬¬­¬­¬¬­¬­­¬¬¬¬¬¬¬¬¬¬¬¬««¬¬¬¬¬¬¬­¬­­¬­¬11111¿11111111111®111111111111111111111111111111®®®¿1¿¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®­®®®­­®®®®®®®®®®®®®­­­­­¬­¬­¬¬­¬¬­¬­¬­¬­¬¬­¬­¬¬­¬¬¬­¬­­­­­¬­­®®­®®®­®®­­­­­­¬­¬¬­¬¬­¬­­­­­­­­­®­­­­­­­­­­¬¬¬¬¬­¬­¬¬¬­­­­¬¬¬­­¬¬­¬¬¬¬­¬­­¬­­¬­¬¬­¬¬¬­¬­­¬¬­¬­¬­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬­­­­1111111111111111111¿111111111111111111111111111111111®®®¿11111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­®­®®®®®®®®®­®®­®­®®®®®­­®®®®®®®®®­­¬¬¬­­¬¬­¬­­­­¬­¬¬­¬¬¬­¬¬¬¬­¬¬­­¬­¬­¬­­¬®®®®®®®®­­­­­­­­­­¬¬­¬¬®­®­­­­­®­­­­­­­­­­­­­­¬­­¬¬­­­¬¬­­¬­¬­­¬­¬­¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬¬­¬­¬¬¬¬¬¬­­­¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬­­­¬­¬®111111111¿111111¿11¿11111111111111111111111®11111111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®­®®®®®®®­®®®®®®®®®®®®®­­®®®®®®®®®®®­­­­­­­­®­¬­­­¬¬¬­¬­­¬¬¬­¬¬­­¬¬­¬¬¬¬¬­­­¬¬¬¬¬­­­¬­®®®®­­­­­­­­­®®­®­­­­­­­­­­­­­¬¬¬­­¬¬­­¬­­¬­¬­¬­­¬¬­¬¬­¬¬¬¬­¬¬­¬­¬­¬¬¬­¬¬­¬­­­¬­­¬¬¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬­­­®®11111®®®11111111111111111¿1111111111®¿11¿11¿11¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­¬¬­¬­¬­¬¬­­¬¬­¬­¬­¬­­­­­­­¬¬­¬¬­­®®®®®®­­­­­­­­¬­­¬­­­­­®­®®­­­­­­­®­­­­­­­­­­¬¬­¬­­­¬­­­¬­¬­¬­¬­¬¬¬¬¬¬­¬¬¬¬­¬¬­­¬¬­¬¬­­¬¬¬­¬¬¬¬­­­¬­¬¬¬¬¬¬¬¬¬¬¬®¬­¬­¬¬­®­­­­­­¿11111¿®­­®1111111®®®1111111®®1111111®¿11¿1¿11¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­®®®®­®®®­®®®®®­®®®®®®®®­®®®®­®®­­®®®®®®®®®®®­®®®®®­­­­®­­¬­¬¬­­¬­¬¬­¬­¬¬­¬¬­­­¬¬­¬­­­­¬¬­¬¬­­­­­­­®®®®®­®­­­­®®­­¬­­¬­­­­­­­®­­­­­­­­­­¬¬¬­­¬­¬­­¬­¬¬¬­­­­¬¬¬¬­¬­­¬­¬­­¬­¬¬¬¬­¬¬­¬¬¬¬­­­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­­­­­­­­11111®111¿1®®®®®1®®®®¿1111111®¿¿¿¿¿¿¿¿¿¿¿®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®­®®®­®­®­­®®®®®®®®®­­®®®®­­­­­­®¬¬­¬¬­¬­¬­­¬­­­­¬­­¬¬­¬­¬­¬­­­­­­¬­®®®­®­­­­­­­­®­­­­­­­­­­­­­­­­®­­­­¬¬­­¬­¬­­¬¬­­­­­¬­¬­¬¬­¬­¬­¬¬­¬­¬­­¬¬­¬­¬¬­¬­­¬¬¬­¬¬¬­­­­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­­­®®1111®®1111®®®11®®®®®®®®®®¿1111111®¿1¿11¿¿¿¿¿¿¿¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®­®­­®®®®®®®®®®®­­­®­®®®­­­­­­­¬¬­­¬¬¬­¬­­¬­¬­¬¬¬­¬¬¬­¬¬¬¬­¬¬¬­­­­­­­®®®®®­­­¬­­­­­­­­­­­­­­­­­­¬­®­­­¬­­­­®­­­­­­­¬­¬¬¬¬­­­­¬¬¬­¬­¬­­¬¬­­¬¬­¬¬¬­­¬¬¬­¬¬­¬¬¬­¬¬­¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬­­­­¬¬­®11®®®111111111¿®®®®®1111111®1¿¿¿111¿¿¿11¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®­­®®®®­®®®®®®®®®®­®®®®®®®­­®­­®®®®®®®®®®®®®­®­­®®®®®­­­¬¬­¬¬¬¬¬­­­¬¬­­¬¬­¬¬­¬­¬¬­¬¬¬¬­¬¬¬­­¬­­­­­®®®®®®­­¬¬­­­¬­­­­®­­¬­­­­­­­¬­­­­­­­­­­­­­­­­­¬­¬¬­­¬­­­­¬­­­¬¬­¬­­­¬­¬­­¬¬¬­¬­­¬¬­­­¬¬¬­¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­­­­¬¬¬­11­®®®111111111111¿®®®®1111111®1¿11¿¿¿¿¿1¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®­®®­®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®­­­­®®®®¬­­­­­­¬­¬¬­­­­¬­­¬¬¬­¬­¬¬¬­¬¬­¬­­­¬­­­®®®®®®®®­­­­­­®­­­­®­­­­¬­­¬­­­­®­­­®­­­­­¬¬¬­¬¬­­¬­¬­­¬­¬­­­¬¬­­¬­¬­¬­¬­­¬¬¬­­¬¬­¬¬¬­¬¬¬¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­¬¬¬¬¬®111®®®111111111111¿®®®®®1111111®¿1¿¿¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®­­®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®®®®­®­­­­­­¬¬¬­­¬­­­¬­­­¬¬­¬¬­¬­­¬­­¬¬­­¬­®®®®®®®®­­­­­­­­®­­­¬¬­­­­­­­®­­­­­­­¬¬¬¬¬¬¬­¬­­¬­­­¬­¬¬­¬¬­­­­®­­¬­¬­¬¬­¬­¬¬¬¬­¬¬¬¬­¬­¬¬­¬¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬­¬¬­¬¬¬­®¿11¿­®®®11111111111111®®®®®1111111®®¿¿¿¿¿1¿¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®®®®®®®®®®®®®®®®­­®®­®­®®­®®­®®®®®­®®®®­®®®®­®®®®®­­®®®®®®®®®®®®®®®­­­­®®®®­­­­¬¬¬­¬­¬¬¬­­­¬¬­¬¬­¬¬­¬¬¬¬­¬¬­¬­­­­®®®®®®®®­­­­­®®­­­­®®­®­­­¬­®­¬­­­­­­­­­®­­­­­­­¬¬¬¬­­­¬­­­­­¬­­¬­¬­¬¬­¬¬®¬¬­­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬­­­¬­­¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­­­¬¬¬­¬¬­®11­®111111111111111111®®®®®®®®1111111®®¿1¿¿1¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®­­®­®®®®®®®®­®­®®­®®­®®®­®®®®­­®®®®®­®®­®®®®®®®®­­­®®®®®¬­¬­­¬­­¬­¬¬­­­­¬­¬¬­¬¬­¬¬­¬¬­­­­¬¬¬¬®­­¬­®­®®®®®­­­®­­­­­­­­¬¬­­­­­­­­­­­®­­­­­­­­­­­¬­­­­¬­­­­­­­­¬­­­­¬¬¬¬­¬­­¬¬­­­¬¬­¬¬­¬¬­­¬¬¬¬¬­­­®¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬­­­­­­­¬¬­¬­­®®®®11®­­®111111111111111111®®®®®®®1111111®®¿¿¿¿¿¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­®®®®®®®®®­®­­®®­®®®®®®®­®®®®®®®®®®®®®®®®®­­­­®®®®®®®­¬­¬¬¬¬¬¬¬­¬¬­¬­­¬¬­¬¬­¬¬¬¬­­¬¬­¬¬¬­­­­­­­­®®®®®®®­­®­­­­­­®®­¬¬­­­¬­®®®­­­­­­­­¬¬¬¬­¬¬¬¬¬­¬­­¬¬­¬­¬­­­¬­¬­­¬¬­¬­­¬¬­¬¬­­¬¬­­¬¬­­¬¬­­¬¬¬¬¬¬¬¬­¬­­¬¬­¬¬¬¬¬­®®®111®®®1111111111111111111®®®®®1111111®¿¿¿¿¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®­®®®®®­®­®®®®­®­®®®®®®­­®­­®®­®®®®­®­­®®®®­®®®®®®®®®®®®®­­¬®­¬¬¬­¬¬¬¬­­¬­¬¬­­¬­­­¬­­¬­¬­®­¬­­­®®®®®®®®­­­­­­­®®®®­­¬­­­¬®­­­­­¬­­®­­­­­­­®­­­­¬­­­¬­¬­¬¬¬¬¬¬­­­¬¬­­¬¬­¬­­¬­­¬¬­¬¬­¬¬¬¬¬­¬­¬­¬¬­­¬¬¬­¬­­¬­¬¬¬¬¬¬¬¬­¬­¬¬­¬¬­¬¬­®®®®1111¿11111111111111111111111®®®®®1111111®¿¿¿¿¿¿¿¿¿®®®¿®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­®­­®®®®­­®®­®®®®®®­­®­®­­®­­®®­­­®­­®®­®®®®®®­®®®®­­­­­­­¬­­­¬¬¬­¬­­¬­¬¬­­­­¬­¬¬­¬¬®¬­­­¬­­®®®®®®­­­­­­®­®®®­­¬¬­®­¬­­­­­­­­¬®­­­®®®®­­­­­­­­¬­­¬­¬¬¬¬¬­¬¬­¬¬¬­­¬¬­­­¬¬­¬¬­¬¬­­¬­¬­­¬¬­¬¬­¬­¬­¬­¬­­­¬­­­­¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬­¬­­¬¬­®®®®11111111111111111®111®®®®®®®1111111®¿¿¿1¿¿¿¿®®®®¿¿®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®­®®®®®®®®®®®®®®®­­®­­®®®­­®®®®®®®®®®­®­­®­®®®®®­­®­®®®®®®­®®®®®®­­­­®¬¬­­­­¬­¬­¬­¬¬­¬­¬­¬¬­¬¬­¬­­¬¬­­­­­­­®®®®®®­­­­­­­­®®­­­­­¬¬­­¬¬­®¬­­¬¬®®­®®­­­­®­­­­­­­­¬¬­¬¬¬¬¬¬¬­­¬­­­¬­­¬­¬¬­¬¬¬­¬¬­¬­¬­¬¬­­¬­­­¬­¬­¬­¬­¬­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­­­­¬­¬¬­­®®1111111®®®®1111¿®®®®®®®®®®®1111111®®®¿¿11¿1¿¿¿®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®­®®®®®®®­®®®®®­®®­­®­®­­®­­®®®®®®®®­­¬­­­­­­­­¬¬­­¬­¬¬¬¬­¬¬¬­­¬¬¬­¬¬­¬¬­¬­¬¬­¬­¬¬¬¬­­®®­®®®­­­­­­­®®®®­­®¬­­®¬­­­­­­­®®®®®­­®­­­­­­®­­¬­­¬¬­¬­­­­¬¬­­¬­­­­¬­­¬­­¬¬¬­¬¬¬¬¬¬­¬­­¬­­¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­­¬¬­¬¬­­¬¬11®®®®®®®®®®111®®®®®®®®®®1111111®®®1¿¿11¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­®®®­­®®­®®®®®­®­®­­­®®­­­­­­­®®®®®­®­¬­¬¬¬¬¬­­­­¬¬¬¬­­­¬¬­­¬¬­¬¬¬¬¬¬­¬­­¬¬­¬¬¬­¬¬¬­­­­­®­®®­­­­­®®®®®®­­­®®®¬®®®¬¬¬­®®®®­­­­­­­­­¬¬­­­­­¬­¬¬­¬­­­­­¬­¬¬¬­¬¬­¬¬­­­­­­¬­¬¬­­¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬­­¬¿11®®®®®®®®®®11®®®®®®®®®®®1111111®®1¿1111¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®®®®®­®­­®®®®®®­­®­­®­®­®®­®®®®­®®®®®®®®¬­¬¬­­¬¬¬­­¬­­¬¬­­­­­¬­¬­¬¬­¬¬­­¬¬­¬¬­¬¬­¬­­¬­­­­­®®®®­®­­­­­­­®®®®®®®®®­­­®­®®®®®¬¬­­­®­®®®®®­­­­­­­­­­­­­­­¬­­­¬¬­¬¬­­­­¬­¬­¬¬¬­¬­¬¬¬­¬­­¬­­­¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬­¬­¬­­­­­¬¬¬­®1®®®®®®1®®®®®®®®®®1111111®®®¿1¿¿¿¿¿1¿¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®­®®®®®®­­®­­®­­®­®­­­®®®®®®­®®­®­­¬¬­­­­®­¬¬¬­¬¬­­­­­­¬¬­­­­¬­¬¬­¬¬­­¬­¬¬­¬¬­­­¬¬­­­¬­®®®­­­­­­­®®®®®®®®®®®®¬¬­¬¬¬®®®®¬¬­¬­­­®®­­­­®­­­­­­­­­­­­¬¬­­¬­¬¬­­­¬¬­­¬¬¬­¬­¬­­¬¬­­¬¬­­­­­­¬­­­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­­¬­¬¬¬­¬¬­¬¬1®®®®®®®®®®®®®®®®®1111111®®®®®¿¿¿¿¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®­­®­®®®®®­­®­®®­­­®®®®®®®®®®®¬¬­¬¬­­­¬¬¬¬­­¬­­­­­­­¬¬­­­­­­­­­­¬¬­¬¬¬¬¬¬­¬­­®­®®­­­­¬­­­®®®®®®®®®®®­­­¬¬¬­­®®®®­¬¬¬­®­®­­­®­­­­­­­­­­­­¬­¬­¬¬­­­­¬­­¬¬­­¬¬­¬¬­¬­¬¬­¬¬­­­­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­­¬­­­­¬¬­­­¬­®11®­®®®®®®1®®®®®®®®¿111111®®®®®¿¿¿1¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®­®®®®­­®­®­­­­®­­®­­­®­®®®®®®®®®®®­­¬­¬­®¬¬¬¬¬­­­­­¬­¬¬¬­¬®­­¬¬¬¬­­¬¬¬­­¬¬¬¬­­¬­®®®®­­­­­­­­­®­­­®®®¬¬­¬­®®®¬¬¬­­­­®­®­­­­­®­­­­¬­­­­­­¬­¬¬­¬­­­¬¬­­­­¬¬¬­­¬¬­¬­¬¬­¬­¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬­¬­¬¬­¬­¬®11¿1®­®®1®®111111®®®®®®®®111111®®®®®¿¿¿¿¿1¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®­®­­®­­­®­­®­­­®®®®®®­®®®®®¬¬¬­¬­­¬¬¬¬­­­­­­­­­¬­­­­¬­¬¬­¬¬­¬¬­¬­¬­­¬¬¬¬¬­­­®®®®­­­­­­­­®®­­­®®®®®®®¬­¬¬­¬­­®®®®®­­¬¬¬­¬­¬¬­®®®¬®­­­®­­­­­­­­­­­­­­¬¬­¬­­­­¬­¬­­­¬­­­¬­¬­¬¬­¬¬¬¬­¬­®¬­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬­¬¬­¬¬­¬­­­®1111­1®®11111111®®®®®®®111111®®®®®®11¿¿1¿¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®­®®­®®®®®­®­­®­­­®­­®­­®­®®®®®®®®®®®®­®®®­¬¬­¬­­¬¬¬¬­¬¬­¬­¬­­­­­­­­­¬¬­¬¬­¬¬­¬¬­¬­¬¬­¬­­­­­­­­®®®®®®®­­­­®®®®­®¬­¬­¬¬­­¬®®®®­­­­­¬­¬­®®®®®®®®­­­¬­­­¬¬­¬­¬¬¬¬­­­­­­¬­­¬¬­¬¬¬­¬­¬¬­­¬­­­®¬­¬­­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬­¬­­¬­¬­¬­®1111­­®11®¿11111111®®®®®111111®®®®1¿1¿1¿¿1¿¿¿1¿®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®­­­®®®­®­­®­­®®­­®®­®®­®®®®®­­­­­¬­®­¬¬­¬­¬­­­­­­¬­­­­¬¬¬¬­­¬¬­¬¬¬­¬¬­¬¬¬¬­­­­¬¬®®®­­­­­­­®¬­­­¬¬­­­®®®®­­­­­®®®®­®®­®­­­­­­­­­­­­­­¬­¬­­­¬¬­­¬­¬­­­­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­­­­­­­¬¬­¬¬­­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬­­­¬¬­­­­­¬­¬¬¬¿11111­­11®111111111®®®®®®®®®®®®®®®¿11¿¿111¿¿¿¿111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­®­®®®®®­®­­®®®­­®­®®­®­­®®­­®­®®®®®¬­­¬¬­­¬­­¬¬¬­¬­­¬­­­­¬­¬¬¬­¬­¬¬­¬¬­­¬­®®­­®­­¬­­­­­¬­­¬¬­¬­¬¬­¬­­®®®®­­­­­­®­®®®­­­­­­­­¬­­¬¬­­¬¬­¬¬¬­¬¬­¬­­­­¬¬­¬­­¬­­­­¬­¬¬¬­­­­¬­­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬­­¬­¬¬­¬­¬­¬¬­¬¬­¬­¿11111­­­11111111111®®®®®1®®®®®®®1111111¿¿¿¿11¿®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®­®®®®®­®®®®®­®­®­­®­­®­­®­­­­®®®®®®®®®®®­¬­¬­­­¬¬¬­­­¬­­­¬­­¬­­­¬¬­­¬­¬¬­¬­¬¬­¬¬­¬­­¬­­­®®­®­­­­­­­­­¬­¬¬­­¬­¬­­­­­­­­­­­­­®­®®®®®®­­­­­­­­­­­­­­­¬­¬¬¬­¬­¬¬­¬¬­¬­¬­¬­®¬¬­¬¬­­­­­¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­­¬¬¬­­¬¬­¬­­¬¬­­¿1111111®®1111111111®®®®111®®®®®®®¿¿¿11111111¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®­®®®®®­®®®®®®®®®®­®®®®­®­®®®®®®®®­­®­­®­­®­­®®®®®®­®®®¬­¬­­¬¬¬­­­­­¬­­­­¬­¬­­­­­­­­­­¬¬­¬¬¬­¬¬¬¬¬­­¬­­¬­­®­­­­­­­­­­­­­­­®®¬¬­¬¬­­¬­­®¬­®®­­­­­®­®®®®®®­­­­­®­­­¬­­­­­­­¬­¬­­­­¬­­­¬¬­¬¬­­­­¬­¬¬­¬¬­¬¬­­­­­­­­­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬­¬­¬­­­­­¬­¬¬®¿¿111¿­®1111111111111®®111®®®®®®1¿1¿¿1111111¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®­®­®®®®®­®®®®®®®®®®­­­®­­­­­­®­­®®®®®®®®®­¬¬¬¬¬¬¬¬¬¬­­­­­­­­­­­­¬­¬­­­­¬¬­­­¬¬­¬¬­­­¬¬¬¬¬­­­­®­­­­­­­­­­­­­­®­­¬­¬­¬­­­®­¬¬¬¬­­®®®®®®®®®®®®®®­­­­®­­­­­­¬¬­¬®­¬­¬¬­¬¬­¬­­¬¬­¬¬­­¬­¬­¬¬­¬¬¬­­­­­­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬­­¬¬¬­­¬­­¿1111­®1111111111111®®®®®®1111®®®¿11¿1111¿11¿11¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®­®®®®®®­®­­®­®­­­­­®®­®­®®­¬¬¬¬­¬¬¬¬¬¬­­­­­­¬­­­­­­­­­¬¬¬­¬¬¬­¬­¬¬­­¬¬­­®®®­­®­­­­­­­®­®­­­¬­¬¬­®®­¬­¬¬­®­®®®®­®®®®®®®®®®®®®®®­­­­­­­­­­®­¬­¬¬­¬­­­¬¬¬­¬­­­­¬­­¬­¬¬­¬­¬¬¬­¬­­­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­­¬­¬¬­¬¬­¬¬¬­¬¬­¬¬®¿1¿11­­®111®1111111111®®®®1111®®®®11¿1111¿11¿¿¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­®­®®®®­®­­­­®®®®­­®­­­­­®®®®®®­­¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­­­­­¬¬­­­­­­¬­¬­­­¬­­­­¬­­¬­®­­­­­®­®­®®®­­­¬­­¬®­®­¬­¬­¬¬®­­­­®­®®®®®®®®®®®®®®­­­­­®­­­­­­¬¬­­­­¬¬­¬¬¬­­¬¬­¬¬¬­­¬¬­¬¬­¬¬­¬­¬­­­®­­¬¬­¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬­¬¬­¬­­¬¬¬¬¬®11¿1­®111®1111111111®®®11111®®®1¿11¿¿11¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®­®®®®®®®®®®®®­­®®®­®­®®­®®®®®®®®®­­­¬¬¬¬¬­¬­¬¬­¬¬¬­­­­­¬­­­­­¬­¬¬¬¬­¬¬­¬­­­­­¬­­­®®­­­­­®­®®¬­­¬­¬¬­­­­¬­­­­­­­­®®®®®®®®®®­­­­­­­­­­­¬¬¬¬­­­¬¬­­­¬­­¬­¬­¬¬­¬­­¬­¬¬­­­­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬­­¬¬¬­¬¬­¬¬­¬¬®1­®1111111111111®®®®®11111®¿11111111¿¿¿¿1111¿¿¿®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­®®­­­­®­­­­­¬­¬¬­¬¬­¬¬¬­­­­­­­¬¬­­­­­­­¬¬¬­¬¬¬­­¬¬­­­®®­­­­­­­­­­®®®­­­­¬­­­¬­¬¬­­¬­®­¬¬­¬¬¬­­­­®®®®®®®®®­­­­®­­¬­­¬¬¬­­­¬­¬­¬­¬¬­­­­­®­®¬­¬¬­¬­¬¬¬­­­¬¬¬­¬¬­¬¬­¬¬¬¬­­¬¬¬­­­­­­­­­¬¬¿1­¬­®111­­1111111111®®111111111111111¿111¿111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®­­®­­­­­­­­­­­­®­­­­­­­­¬¬­¬¬­¬­¬­¬¬­¬­­­¬¬­­­­­­¬­­­­¬¬­¬­­­¬­­­­¬­­­­­­­­¬­¬­¬¬¬¬¬¬­¬­­®®­­­­¬­¬­®®®®®®®®®®®­­­­®­­­¬­¬­¬¬­¬¬­­­­¬­­­¬­¬¬¬­­­®®®­­¬­­¬­¬¬¬¬¬¬¬­¬¬¬­­­¬­¬­¬­¬­­¬¬¬­­­­­­­­­­­­¬­®®®®¿­­®111­­­1111111111®®®11111111111111¿¿11¿1¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­­®®®®®®­­­­­­­­­®®®­­­­­­¬­­¬¬¬¬¬¬­¬¬¬­¬¬¬­¬¬¬­¬¬¬¬­¬­¬­¬­¬¬¬¬­®­­­­¬­­­­­®­­­­­®­¬­¬¬¬­­®­­¬¬­­®®®­¬­¬­­­­®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬­¬­®­®¬¬­­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­­¬¬¬¬­­¬­­­­¬­­­­¬¬®®®1­­11­®111111111®11111111111111¿11111¿¿1¿¿1®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®®®®®®®­­®­­­­®­­­­®­®®®­­­­­­¬­­¬¬­¬¬­¬¬­¬¬­­­¬­¬­­¬¬­¬¬¬­­­¬­¬­­¬­­­¬­­­­­­­­­¬­­¬¬­¬­¬­­­­­­®®­¬­¬­­­®®®®®®®®®®®®®­­®­­­®­­¬­­­¬¬­¬­¬¬¬¬­¬­­­®®®®®®®­¬­¬­¬­¬­¬¬¬¬¬­­¬¬¬­¬¬­¬¬¬¬­­­­­¬­­®®1­­­­11®111111111®®1111111111111111111¿11111¿¿¿¿¿¿®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®­­­­­­­­­­­­­­­­®®­­­¬­¬¬­¬­¬¬¬­¬­­­­­­­­­­¬­¬¬¬­­­­­­­­­­­­­­­­­­­®­­­­­­­¬¬¬­­­­­­­®¬­®®®®®®®®®®®®®®®®­­­­®®­­¬¬¬­¬­¬¬­¬¬¬¬¬­­¬¬­­­­®®®®®®®­¬¬¬¬­¬­¬¬¬­¬¬­¬­­­­¬­­¬­¬­¬­­­¬¬­­­­­®­­­­­®®®1­­­®11­111111111®®111111¿¿1¿11111¿¿1111111¿¿¿1¿¿¿1¿®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®­­­­­­­­­­®®®®­­¬¬¬­¬­¬­­­­®­¬­­­­¬¬­­­¬­¬¬­¬¬­­­­­­­­­­­®®­­­®­­­­­­­­¬­¬­­®­¬­¬­­­­®®­­­®®®®®®®­®­­­®®®­¬­­­­¬¬¬¬¬­¬¬­¬­­¬­­¬­­­­®®®¬¬­¬¬­­¬¬¬­¬­­­¬¬¬¬¬­¬¬­¬­¬¬¬¬¬­­¬­­­­­¬­¬­®11­11®1111111®®®111111®¿11111111¿1111111¿1¿¿1¿11¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®­®®®­®®­­­­­­­­­­­­­­­­­®®®®­­­­¬¬­¬¬­¬¬­­­­­­¬­­­­­­¬®­­¬­¬¬­­­­­­­­¬­­­­¬­­­­­®®­­­­­­¬¬­¬­¬­¬®­¬­¬¬­­­­­­­­®®®®®®­®­­®­­­­¬¬­¬­­­¬­­¬¬­¬­­¬­­¬­­­®®®®®®¬­¬¬­¬¬­­¬­­¬¬­¬¬­­¬¬­¬­­¬­¬¬¬­¬­­­­­­­­¬11­­­­®1®­­1111®®®111111®1111111111¿1111¿¿¿1111¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­­­­®­­­­­­­­®®®®®­­­­¬¬­¬­¬¬­¬¬­­­­­­­¬­­­¬­­­­­­¬¬­¬­¬­­­­­­­­­¬¬¬¬­­­­­­­­­­­¬¬¬¬­¬­­¬­®­­­­®­­­­®®®®®®­­­­­­­­¬¬¬¬¬¬­­­¬¬­¬­¬¬­¬­¬¬¬­­­®®®®®¬¬­¬­¬­­¬­­­¬¬­¬¬­¬­¬­¬¬¬¬­¬¬­¬­¬­­­­­­­­­­­­¬­­­®®­¬¬¬11®®®®®1¿11111111111¿¿1¿¿11¿¿¿11111¿11¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­­®­­­­­­­­­­­®­­­­­­®®®®­­­­¬­¬­¬¬¬¬­¬¬­¬­­¬­­­¬¬¬¬¬¬¬­¬¬­­­­­­­­­­­­­¬­­­­­®­­¬¬­¬­¬­®­­­­­­®®­­­®®®®®®®®­­­­­­­­­¬¬­­­­¬­¬­¬¬­¬¬­¬¬­­­­­­®­¬­­¬­­¬­¬­¬­¬¬¬¬­¬­­¬¬­­­­¬¬­­¬­¬­­­­­­­­­®1¿®®­¬­­®111­®®®®®®11®®11111111111111111¿1111111111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­®®®®®®®®­­­­­­­­­­­­­­­­®®®­­­¬¬­¬¬­¬¬¬­¬¬­¬¬¬¬­­­­­¬¬¬¬­¬¬¬­­­­­­­­­­­­¬­®­­­­¬¬¬¬¬­­¬­­­­­­­­­­®®®®­­­­­®®®®®®®®®®®®­­­­­­­¬¬­¬­­¬¬­¬­­¬­¬­­¬­¬­­­­®¬¬¬¬¬­¬¬­­¬¬­¬­­­¬¬­¬­¬­¬¬¬­­­­­­­­­­­­­11®®­­­­®111­®®®®®®11®11111111111111111111111111®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­®­­®­®®­®­­®­­­­­­­­­­­­­­­­­­­®®®¬¬¬¬¬¬­­­­¬¬­­­­¬­¬¬¬­­­¬¬¬¬­­­¬­­­­­®­­­­­­­®¬­­­­®®­­­­­­¬¬­¬¬¬¬®­­­­­®®®­­­­®®®®®®®­­­­¬­¬­­­­­¬¬­¬¬­­­­­¬­­­­­­­®®®®¬¬­¬­­­¬­­­¬¬­¬¬­¬­­­¬¬­¬¬­­¬¬¬¬¬¬¬­­­¬­­­­­­­­­­­­®11®­­­­®11®®®®®®®®®11®111111111111111111¿111¿11111111®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­­­­­­­­­­­®­®­­¬¬¬­¬¬­­­­­­­­­­­­¬¬¬¬­¬¬¬¬¬­­¬¬¬­­­­­®­­­­­­­­®®®®­­®­¬­­­®­­­­­®­®®®®®­®®®®®®®­­­­­­­­¬¬­¬¬¬¬­­­¬¬­¬¬­¬­­­¬¬¬­­­­­®®®®®­­­¬­¬­¬­¬¬­¬¬­¬¬­¬­­¬¬¬¬­¬¬­¬¬­¬­¬¬¬¬¬­¬­­­®­¬®111­­­®®®®®®1®11111111¿111111111111111111111¿¿®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®­®®®®®­­­­­­­­­­­­­­­®®®­­­¬¬­¬¬­­®­¬¬­­­­­­¬¬­¬¬¬¬­­­­¬¬¬­­­­­­­­­­­­­®­®®­­­¬­¬­­­­®¬¬¬®­­®®®®®®®­®®®­­­¬¬­¬­¬­¬¬¬¬­¬¬­¬¬­¬¬­¬­­¬¬­­®®®­¬¬­¬­¬­¬¬­­¬­¬­¬¬­­¬­¬­¬­¬¬¬¬¬­­®­­­¬¬®®111®®®®®®¿1®®®®®®®®®®®11¿11111111111¿1111111111111¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­­®­­­­­­­­­­­­­­­­­¬­®®®®®®­­¬¬­¬¬­¬­­­¬­¬­­­­­­­¬¬¬¬­­¬­­­¬­­­­­­­­­­­¬­­¬®®®®®®®­­¬­­­­­­¬­¬­­®­¬­­®­®®®®®®®®®®®­­­­¬¬¬¬­­¬­¬¬­¬¬­¬¬­¬­­¬­¬®­­¬¬­¬­¬­­­­¬­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­­­­­­­­­®®1111111111¿1111111111111¿1111111111¿®®®11111111111¿¿111¿1111111¿¿11¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­®®®­®­­­­­­­­­¬­­­­­­­­­®®®®®®®¬¬­­¬¬¬¬­­¬­­¬­­¬­­¬¬¬­¬¬­¬­¬­­­­­­­­­­­¬­­­­­­­®®®®®®­®­­­­¬¬­¬¬­¬­®­­­­®®­®­­®­®®®®®®®­­­­­­­¬¬­¬­¬¬­¬¬­¬¬­¬¬¬­¬­­­­¬­­­®®¬¬­¬¬¬¬¬­¬¬­¬­¬¬¬­­¬¬­­¬¬¬¬­¬­­¬¬¬­­¬­®­­­­­­­¬¬®®1111111111111111111111111111111111111111111111®®111111111¿111111¿¿11111¿¿¿¿®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®­­­­­­­­­­­­­­®®®®®®­­­­¬­¬­¬­¬¬¬­¬¬­­­­­­¬¬­¬¬¬¬­­­­­­­­­­­­­­¬­®®®®­­­­­¬­­­­­¬¬®­­­®®­®®®®®®®­­­­­­­¬¬¬­¬¬¬¬¬¬­­¬¬­¬­¬­­­¬­­­­®®®­®¬¬¬¬­­¬¬­¬­­­­­¬¬­¬­¬¬¬¬­¬¬­­­­­­­­­­¬­®®®®¿11111111111111111111111¿111111111111111111111¿®1111111111111111¿111111¿¿¿11®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­®®¬¬¬¬­¬¬¬­¬­¬¬¬­­­­­­­­­­­­­®®®®®­­­¬­­­­¬¬­®®¬­­­­­­­­­­®­¬¬­¬­¬­¬­¬¬¬¬¬¬­­­­¬¬­¬¬­¬¬­­¬­¬¬­¬¬­¬­®®®®­­®®­¬­­­¬­¬¬­­¬­¬­¬¬­­¬­­¬¬­­¬­¬­­­­®¬¬­®®¿¿11111¿111¿1111111111111111111111®®111111111¿111111111111¿¿¿¿¿®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®­­­®®®®®­­­­¬¬¬­¬¬¬¬¬¬­¬¬­­­­­­­­­­­­­­­­®®®®®®®®­­¬¬­­­­­¬­­­­­­­­­­­­­­­­®­­­­­¬­­­­­¬¬­¬¬¬¬¬¬¬­­¬¬¬­­¬¬­¬­¬¬­¬¬­¬®®­­­­­­®¬¬­¬¬­¬­¬­¬¬­¬¬­¬¬­¬¬¬­¬­­­¬­­¬¬­¬­¬­­­­­­­­­®®®®®®®®®¿111®®¿1111111111111111111111®111111111¿1111111111111111¿¿1®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­¬­­®®­­­­­­­­¬¬¬¬¬¬­¬¬¬¬¬­¬­­­­­­­®®®®®®®®®®­¬­¬­­­­­­­­­­­­­­­­­­­­­­¬­­­¬¬­­­¬­­¬¬¬¬­¬­¬­­¬¬­¬¬¬¬¬¬­¬¬­¬­¬¬­®®­­­­­­­­­­­¬¬­¬¬­¬¬­­¬¬¬¬­¬­¬­¬­¬¬¬¬¬­­­­¬¬­­¬¬¬­­­­®®­¬¬®®®®®®®¿11111®®¿1¿11111111111111111111®11¿11111111111111¿1111¿11¿11¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­®®®®­­­­­­¬¬¬¬¬¬­­­¬¬­­¬­¬­­¬­­­­­­­­­®®®®­®®­­­­­­­­­­­­­®­­­­­­­­®®­­­­¬¬¬­­­¬­­­­­¬¬­­¬¬­¬¬­¬­¬­¬¬¬¬­­¬¬­¬¬¬¬­¬­¬¬­¬¬®®®­­­­­­­­­¬¬¬­­­¬­¬­­¬­¬­¬­¬­­­¬­¬¬­­­¬­­¬­­­®­­®®®®®®®®®11111111111®®®¿1111¿®®®®¿11¿¿11111111111111111¿11¿1¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­®®®­­­­­­­­¬­¬¬­­­¬¬¬¬¬¬­­¬¬¬¬­­­¬­­­­­®®®®®®­®®­­®­­®­­­­¬­®®­­­­­­­­­­®­­¬­­­¬¬­­­­­­­­¬¬­¬¬¬¬¬­­­¬¬¬¬­¬¬­¬¬­¬­­®®®®®®®­­®­­­­¬­¬­­¬­¬¬­¬¬­¬¬­¬¬¬­¬¬­¬­¬¬­¬­¬¬­¬¬­­­­­­­®­­­¬­®®®¿®®®®®®®®®®®®®1111111111111¿111111111¿1¿¿1¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®®®®­­®­­­­­­­®®­­¬­­­­­­¬¬¬­¬­¬­¬¬­­­­­¬¬¬¬­­­­­­­­®®®®®®®®®­®­­­­­­­­­¬­­­®®®­­­­­­­­­­­­­­­­­­¬¬­­­­­¬­­¬­­­­­¬¬­¬¬­¬¬­­¬­­¬­¬¬¬¬­¬­¬­¬­®®®®®®®®®®­­­­¬¬¬­­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬­­¬­¬¬­¬­­¬¬¬­­­­­­¬¬®®®®®®®®1®®®®®®®®®®®®®­111111111111¿¿11111111¿¿1¿11111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­­­­®®®­­­­­¬­­­­¬­¬¬­¬¬¬¬¬¬­­­­­­¬¬­­­­­­­­­®­®®®®®®­­­­­­­­­­®­­­­­­­­­­­­­­­­­¬­¬­­­­­­­¬¬¬¬­¬¬­¬­­­­­­­­­¬¬¬¬¬­¬¬­®®®®®®®®®­­­­­­¬¬­­­¬­¬­­­¬­¬­¬¬­¬¬­­¬¬­­¬­¬­¬­­­¬­­¬­­­­­®­­®®®®®®®®®¬¬®®®®®®®®111111111111¿1111111111¿1111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®­­­­­®®®®®®­­­­­¬­¬­¬¬¬¬­¬¬­­¬¬­­­­¬­­­­­®­®­­®®®­­®®®­­­­­­­­­­­­­¬­­­­­­­¬­­­­¬­­¬­­­¬¬­­­­­¬¬­­­¬¬­­­­¬­¬­¬­¬­¬­¬­¬®®®®®®®®­­­­­¬­¬­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­­­¬¬¬­¬­­­¬­¬¬­­­¬­­¬­­­­®­­®®­­­­®®®®®®®®®®111111¿11111111111111¿¿¿1¿¿¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­®­­­­­¬­­­­­¬¬­¬¬­¬¬­¬¬­­­­­­­¬®­­­­­®­®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬­­­­­­­­­®­­­¬¬¬¬­­­¬­¬¬­­­­­­­­­­­­¬­¬¬¬­¬¬®®®®®®®®­­­­­¬¬­­¬­­¬¬¬¬¬¬­¬¬­¬¬¬­¬­¬­¬¬­­­¬­¬­¬­¬¬­¬¬­­­®­­­­¬¬¬¬­­­¬¬¬¬¬1111111111111111111111¿¿1¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­­­­­­­­®­­­¬¬¬¬¬­¬­­­­¬­­­®­­­­­¬­®­®®®®®®®®­­­¬¬­­­­­®®­­­­­­¬¬¬­­­­¬­­­­­­­­­¬¬­¬­¬¬­¬¬­­­¬­¬¬­­¬¬­­¬¬¬­¬­­¬¬­¬­®®®®®®®®­­­¬­­­¬¬­¬¬¬¬­¬­­­¬¬­¬¬¬¬­¬¬¬¬­¬¬­¬­­­­¬¬­¬­­­®­­¬¬­¬¬¬¬­­¬¬­¬¬¬¬¬¬¬¬­­®®111111111111111111111¿¿1¿¿1111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­®­­­­­­­­­¬¬¬­­¬­­­­­­­­­­¬¬¬­¬®­®®®®®®®®®®®®­­­­­­­­­­­®­­­­­­­­¬­¬­­¬­­­¬­­­­¬­¬­¬¬­­¬­­­¬­­­­­­­¬­¬¬­¬¬­¬¬¬¬­¬¬­¬®®®®®­­­¬¬¬­¬¬¬­­¬¬­¬¬¬¬¬­¬¬­¬¬¬¬­¬­¬­¬­­­­¬­­­­­¬­­®­­¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬¬¬­®­11¿¿11111111111111111¿111¿¿111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­®®­­­­­­­¬­­­¬¬¬¬­­­­­­­­­­­­­®®®®®®®®®®®®®®®®®­­¬­­¬­­­®­­­­­­­­­­¬­­­­­­­¬­¬­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬­¬­­¬­¬¬®®®®®­­­­­¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬¬­¬­­­­­­­¬¬­­¬­¬­¬­¬¬­¬¬¬­¬¬­¬¬­¬­¬¬¬¬­¬¬¬¬­­¬¬­­­­®1¿¿1111111111111¿¿111¿11¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­­­­­¬­­¬¬¬­¬­­­­­­®­­­­®®®®®®®®®®®®®®®®®®­¬¬¬­¬¬­­¬­­­­­­­¬¬­¬­¬­­­¬¬­¬¬­¬¬­¬­­­¬­­¬­­­­­¬­­¬­­­¬¬­­­¬¬¬¬¬¬¬¬¬­¬¬­­­­®®®®®­­­­­¬¬­¬­¬­¬¬­¬¬­¬¬­¬­¬¬¬­­¬­¬¬­¬­¬­­­¬­¬¬­¬­¬¬­®­®®­­¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬­¬­­®1¿11111111111111¿1¿¿¿1¿11¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­­­®®­­®­­­­­­­­­­¬­¬¬­¬¬­¬¬¬­­­­­­­­­®®®®®®®®®®®®®®®®­¬­­¬­­®­¬¬­­®®®­­­­­­­­­¬­­­­¬¬¬¬¬¬­¬­¬­¬­­­­¬­¬­­­¬­¬¬­­¬¬¬¬¬¬­¬¬­¬¬­¬¬­¬­­®®®®®®­®­­­¬¬­¬­­¬¬­¬¬­¬¬­¬­¬¬¬¬¬­¬­­¬­­¬¬­¬­¬¬¬¬­­¬¬¬­¬­¬­¬¬¬¬¬¬¬¬¬­­­­­¬¬­¬¬¬­­¿1111111111111111¿¿¿¿1¿¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®­­­­­­­­­­­¬¬­­­­­¬¬®­­­­­­­®®®®®®®®®®®®®®®®®­­­­¬­­­­®®­­­­­®­­­­¬¬­¬­¬¬¬¬­­­­­­­­­­­¬¬­­­­­­¬¬­¬¬¬¬¬­¬­¬¬¬¬¬¬­¬¬­¬­®®®­­­­¬­¬­¬¬­¬­­¬¬¬¬­¬¬­¬¬­¬­¬¬¬­¬­­¬­¬­­¬¬¬­­­®¬­¬­­¬­¬¬­¬¬¬¬¬¬¬­¬¬­¬­­­®11111111111111111111111111111111111¿1¿¿1¿¿11¿1¿¿¿¿¿¿¿¿¿¿¿11¿¿¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/default.cfg.orig������������������������������������������������������0000644�0000000�0000000�00000003430�12327137640�017673� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// // load keybindings // // commands with a leading + will also be called for key up events with // the + changed to a - unbindall // // character controls // bind ALT +strafe bind , +moveleft bind . +moveright bind DEL +lookdown bind PGDN +lookup bind END centerview bind z +lookdown bind a +lookup bind d +moveup bind c +movedown bind SHIFT +speed bind CTRL +attack bind UPARROW +forward bind DOWNARROW +back bind LEFTARROW +left bind RIGHTARROW +right bind SPACE +jump bind ENTER +jump bind TAB +showscores bind 1 "impulse 1" bind 2 "impulse 2" bind 3 "impulse 3" bind 4 "impulse 4" bind 5 "impulse 5" bind 6 "impulse 6" bind 7 "impulse 7" bind 8 "impulse 8" bind 0 "impulse 0" bind / "impulse 10" // change weapon // zoom alias zoom_in "sensitivity 2;fov 90;wait;fov 70;wait;fov 50;wait;fov 30;wait;fov 10;wait;fov 5;bind F11 zoom_out" alias zoom_out "sensitivity 4;fov 5;wait;fov 10;wait;fov 30;wait;fov 50;wait;fov 70;wait;fov 90;bind F11 zoom_in; sensitivity 3" bind F11 zoom_in // Function keys bind F1 "help" bind F2 "menu_save" bind F3 "menu_load" bind F4 "menu_options" bind F5 "menu_multiplayer" bind F6 "echo Quicksaving...; wait; save quick" bind F9 "echo Quickloading...; wait; load quick" bind F10 "quit" bind F12 "screenshot" // mouse options bind \ +mlook // // client environment commands // bind PAUSE "pause" bind ESCAPE "togglemenu" bind ~ "toggleconsole" bind ` "toggleconsole" bind t "messagemode" bind + "sizeup" bind = "sizeup" bind - "sizedown" bind INS +klook // // mouse buttons // bind MOUSE1 +attack bind MOUSE2 +forward bind MOUSE3 +mlook // // default cvars // viewsize 100 gamma 1.0 volume 0.7 sensitivity 3 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/Makefile��������������������������������������������������������������0000644�0000000�0000000�00000000406�12425501423�016260� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������INPUT := gfx/conback.lmp \ maps/e1m1.ent \ maps/e1m2.ent \ maps/e1m4.ent \ maps/e2m2.ent \ maps/e2m3.ent \ maps/e2m7.ent \ default.cfg OUTPUT := quakespasm.pak $(OUTPUT): $(INPUT) ./mkpak.sh $(INPUT) > $(OUTPUT) .PHONY: clean clean: rm -f $(OUTPUT) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/qs_pak/mkpak.sh��������������������������������������������������������������0000755�0000000�0000000�00000005240�12375064103�016266� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # # Copyright (c) 2014, Sander van Dijk <a.h.vandijk@gmail.com> # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. error() { echo "$(basename "$0"): $*" >&2 exit 1 } assert_valid_stdout() { if test -t 1 then error "Usage: $(basename "$0") [file ...] > output.pak" fi } assert_valid_file() { if test ! -e "$1" then error "$1: No such file" fi if test ! -f "$1" then error "$f: Not a regular file" fi if test ! -r "$1" then error "$1: Permission denied" fi if test $(echo -n "$1" | wc -c) -gt 55 then error "$1: Name too long" fi } assert_valid_int32() { if test $1 -lt -2147483648 -o $1 -gt 2147483647 then error "Too much data" fi } octal() { if test $1 -gt 7 then octal $(expr $1 / 8) fi echo -n $(expr $1 % 8) } byte() { echo -en \\0$(octal $1) } little_endian_uint32() { byte $(expr $1 % 256) byte $(expr $1 / 256 % 256) byte $(expr $1 / 65536 % 256) byte $(expr $1 / 16777216 % 256) } little_endian_int32() { if test $1 -lt 0 then little_endian_uint32 $(expr $1 + 4294967296) else little_endian_uint32 $1 fi } zero_padding() { if test $1 -lt 1 then return fi byte 0 zero_padding $(expr $1 - 1) } header() { echo -n PACK little_endian_int32 $1 little_endian_int32 $2 } directory_entry() { echo -n "$1" zero_padding $(expr 56 - $(echo -n "$1" | wc -c)) little_endian_int32 $2 little_endian_int32 $3 } assert_valid_stdout directory_offset=12 directory_size=0 for file in "$@" do assert_valid_file "$file" file_offset=$directory_offset assert_valid_int32 $file_offset file_size=$(wc -c < "$file") assert_valid_int32 $file_size directory_offset=$(expr $directory_offset + $file_size) assert_valid_int32 $directory_offset directory_size=$(expr $directory_size + 64) assert_valid_int32 $directory_size done header $directory_offset $directory_size for file in "$@" do cat "$file" done file_offset=12 for file in "$@" do file_size=$(wc -c < "$file") directory_entry "$file" $file_offset $file_size file_offset=$(expr $file_offset + $file_size) done ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/mk_header.c������������������������������������������������������������������0000644�0000000�0000000�00000003113�11617263603�015432� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* gcc -Wall mk_header.c -o mk_header dumps the bytes of given input to a C header as comma separated hexadecimal values. the output header can be used in a C source like: const char bin[] = { # include "output.h" }; */ #include <stdio.h> #include <sys/stat.h> #include <stdlib.h> int main (int argc, char **argv) { FILE *f; struct stat s; unsigned char *buf, *ptr; const char *output; long i, j; if (argc != 2 && argc != 3) { printf ("Usage: mk_header <input> [output]\n" "Default output file is \"output.h\"\n"); return 1; } if (stat(argv[1], &s) == -1 || ! S_ISREG(s.st_mode) ) { printf ("Couldn't stat %s\n", argv[1]); return 1; } if (s.st_size == 0) { printf ("%s is an empty file\n", argv[1]); return 1; } buf = (unsigned char *) malloc (s.st_size); if (buf == NULL) { printf ("Couldn't malloc %ld bytes\n", (long)s.st_size); return 1; } f = fopen (argv[1], "rb"); if (f == NULL) { printf ("Couldn't open %s\n", argv[1]); return 1; } if (fread (buf, 1, s.st_size, f) != (size_t) s.st_size) { fclose (f); free (buf); printf ("Error reading %s\n", argv[1]); return 1; } fclose (f); output = (argc == 3) ? argv[2] : "output.h"; f = fopen (output, "wb"); if (!f) { free (buf); printf ("Couldn't open %s\n", output); return 1; } for (i = 0, j = 0, ptr = buf; i < s.st_size; ++i) { fprintf (f, "0x%02x", *ptr++); if (i == s.st_size - 1) break; fprintf (f, ","); if (++j < 16) fprintf (f, " "); else { j = 0; fprintf (f, "\n"); } } fprintf (f, "\n"); fclose (f); free (buf); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/quake_retexturing_project.patch����������������������������������������������0000644�0000000�0000000�00000010560�12646150004�021661� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� Index: Quake/gl_model.c =================================================================== --- Quake/gl_model.c (revision 1280) +++ Quake/gl_model.c (working copy) @@ -404,6 +404,8 @@ void Mod_LoadTextures (lump_t *l) extern byte *hunk_base; //johnfitz + extern cvar_t r_externaltexture_fix; //mk + //johnfitz -- don't return early if no textures; still need to create dummy texture if (!l->filelen) { @@ -465,7 +467,17 @@ void Mod_LoadTextures (lump_t *l) if (!isDedicated) //no texture uploading for dedicated server { if (!q_strncasecmp(tx->name,"sky",3)) //sky texture //also note -- was Q_strncmp, changed to match qbsp + { + //mk -- begin + if (r_externaltexture_fix.value) { + if (strstr(tx->name,"sky4")) { + if (CRC_Block((byte *)(tx+1), tx->width * tx->height)==13039) + q_strlcpy(tx->name, "sky1", sizeof(tx->name)); + Con_Printf(" using %s\n", tx->name); + } + } //mk -- end Sky_LoadTexture (tx); + } else if (tx->name[0] == '*') //warping texture { //external textures -- first look in "textures/mapname/" then look in "textures/" @@ -515,6 +527,52 @@ void Mod_LoadTextures (lump_t *l) //external textures -- first look in "textures/mapname/" then look in "textures/" mark = Hunk_LowMark (); COM_StripExtension (loadmodel->name + 5, mapname, sizeof(mapname)); + //mk begin + if (r_externaltexture_fix.value) { + if (strstr(tx->name,"plat_top1")) { + if (CRC_Block((byte *)(tx+1), tx->width * tx->height)==24428) + q_strlcpy(tx->name, "plat_top1_cable", sizeof(tx->name)); + else + q_strlcpy(tx->name, "plat_top1_bolt", sizeof(tx->name)); + Con_Printf(" using %s\n", tx->name); + } + + if (strstr(tx->name,"metal5_2")) { + if (CRC_Block((byte *)(tx+1), tx->width * tx->height)==49173) + q_strlcpy(tx->name, "metal5_2_x", sizeof(tx->name)); + else + q_strlcpy(tx->name, "metal5_2_arc", sizeof(tx->name)); + Con_Printf(" using %s\n", tx->name); + } + + if (strstr(tx->name,"metal5_4")) { + if (CRC_Block((byte *)(tx+1), tx->width * tx->height)==20977) + q_strlcpy(tx->name, "metal5_4_double", sizeof(tx->name)); + else + q_strlcpy(tx->name, "metal5_4_arc", sizeof(tx->name)); + Con_Printf(" using %s\n", tx->name); + } + if (strstr(tx->name,"metal5_8")) { + if (CRC_Block((byte *)(tx+1), tx->width * tx->height)==48444) + q_strlcpy(tx->name, "metal5_8_rune", sizeof(tx->name)); + else + q_strlcpy(tx->name, "metal5_8_back", sizeof(tx->name)); + Con_Printf(" using %s\n", tx->name); + } + if (strstr(tx->name,"metal5_8")) { + if (CRC_Block((byte *)(tx+1), tx->width * tx->height)==48444) + q_strlcpy(tx->name, "metal5_8_rune", sizeof(tx->name)); + else + q_strlcpy(tx->name, "metal5_8_back", sizeof(tx->name)); + Con_Printf(" using %s\n", tx->name); + } + if (strstr(tx->name,"window03")) { + if (CRC_Block((byte *)(tx+1), tx->width * tx->height)==63697) // e4m2 variant + q_strlcpy(tx->name, "window03_e4m2", sizeof(tx->name)); + Con_Printf(" using %s\n", tx->name); + } + } //mk end + q_snprintf (filename, sizeof(filename), "textures/%s/%s", mapname, tx->name); data = Image_LoadImage (filename, &fwidth, &fheight); if (!data) Index: Quake/gl_rmain.c =================================================================== --- Quake/gl_rmain.c (revision 1280) +++ Quake/gl_rmain.c (working copy) @@ -101,6 +101,8 @@ extern cvar_t r_vfog; //johnfitz + +cvar_t r_externaltexture_fix = {"r_externaltexture_fix","0", CVAR_ARCHIVE}; //mk cvar_t gl_zfix = {"gl_zfix", "0", CVAR_NONE}; // QuakeSpasm z-fighting fix Index: Quake/gl_rmisc.c =================================================================== --- Quake/gl_rmisc.c (revision 1280) +++ Quake/gl_rmisc.c (working copy) @@ -47,6 +47,7 @@ extern cvar_t r_noshadow_list; //johnfitz extern cvar_t gl_zfix; // QuakeSpasm z-fighting fix +extern cvar_t r_externaltexture_fix; //mk extern gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz @@ -231,6 +232,7 @@ void R_Init (void) Cvar_RegisterVariable (&r_noshadow_list); Cvar_SetCallback (&r_noshadow_list, R_Model_ExtraFlags_List_f); //johnfitz + Cvar_RegisterVariable (&r_externaltexture_fix); //mk Cvar_RegisterVariable (&gl_zfix); // QuakeSpasm z-fighting fix Cvar_RegisterVariable (&r_lavaalpha); ������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/fitzquake085.txt�������������������������������������������������������������0000644�0000000�0000000�00000143247�11364571402�016363� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ================================================================================ Fitzquake version 0.85, Feb 12, 2009 Filename : fitzquake085.exe Author : John Fitzgibbons Email Address : johnfitz@u.washington.edu Author's Homepage : http://www.celephais.net/ Fitzquake Homepage : http://www.celephais.net/fitzquake Fitzquake is a modified glquake based on the source code released by id Software. My primary focus is fixing a lot of the rendering bugs which made glquake inferior to the software renderer. My secondary focus is adding conveniences for mappers and general users. I am also slowly adding support for new modding or mapping features such as skyboxes, fog, and colored light. While I have made extensive changes to the code, I pretty much use the same OpenGL features that the original glquake uses. Therefore, if you can run glquake, you can probably run Fitzquake. I am not finished working on this project, so bug reports and feature requests are welcome. Acknowlegements -------------------------------------------------------------------------------- id Software, LordHavoc, Bengt Jardrup, Baker, Aardappel, SmallPileOfGibs, FrikaC, Vondur, JPL, Negke, preach, Topaz, Tomaz, Tonik, Radix, EvilTypeGuy, NightBringer, MH, Tyrann, Spirit, Fett, Maddes, Craig Wills, Heffo, Riot, Gleeb, Speedy, people in #flipcode, & others for their feedback, tutorials, code, testing, and assistance. Copyright / Permissions -------------------------------------------------------------------------------- Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. History ================================================================================ changes in 0.85 --------------- - increased limits - added a network protocol 666, which supports higher limits, entity alpha, and more (see command "sv_protocol") - can load and play all known limits-breaking maps, including masque, warpspasm, indian summer, sickbase, 768_negke, digs04, omlabx, and bod. - increased MAX_MODELS from 256 to 2048 (and MAX_MOD_KNOWN from 512 to 2048) (requires the new protocol) Prints a warning if you exceed the old limit. - increased MAX_SOUNDS from 256 to 2048 (requires the new protocol) Prints a warning if you exceed the old limit. - increased the upper limit for the "max_edicts" cvar to 32000 (requires the new protocol for entities past 8192 to play sounds) - models with more than 256 frames can now actually use those frames (requires the new protocol) - fixed crash when marksurfaces > 32767, raising the effective limit to 65k. Prints a warning if you exceed 32767. - fixed crash or other weird behavior when faces > 32767, raising the effective limit to 65k. Prints a warning if you exceed 32767. - fixed crash when nodes > 32767, raising the effective limit for leafs+nodes to 65k. Prints a warning if you exceed 32767. - increased clipnode capacity from 32k to 65k. Prints a warning if you exceed 32767. - increased MAX_MAP_LEAFS from 8192 to 32k (these are visleafs, not total leafs.) Prints a warning if you exceed the old limit. - increased MAX_STATIC_ENTITIES from 128 to 512. Prints a warning if you exceed the old limit. - increased MAX_VISEDICTS from 256 to 1024, which should fix static entities flickering in large maps. Prints a warning if you exceed the old limit. - increased MAX_EFRAGS from 640 to 2048. Should reduce the "Too many efrags!" messages. Prints a warning if you exceed the old limit. - increased MAX_LIGHTMAPS from 64 to 256, meaning you can load 4 times as much lightmap data before getting an "Allocblock:full" error. Prints a warning if you exceed the old limit. - increased MAX_GLTEXTURES from 1024 to 2048 - increased MAX_BEAMS from 24 to 32 and MAX_TEMP_ENTITIES from 64 to 256, so you can have more lightning bolts now - increased increase MAX_DLIGHTS from 32 to 64 - eliminated "packet overflow" errors in single-player mode on all known maps, by increasing MAX_DATAGRAM from 1024 to 32000 (NET_MAXMESSAGE and MAX_MSGLEN were also increased accordingly.) In multiplayer (including COOP,) the MAX_DATAGRAM size is 1400 because the MTU on most internet routers is ~1450, and anything above this could get fragmented and lost since datagram packets use UDP. Prints warning when packetsize exceeds the standard datagram size. - increased signon buffer capacity, should eliminate sz_getspace errors (example: hard mode coop crash on Travail's qte2m1.bsp.) Prints a warning when signon buffer is too big for standard servers. - "no free edicts" error now spits you back to the console instead of crashing - visual improvements - added model interpolation for animation and movement. See cvars r_lerpmodels, r_lerpmove, r_nolerp_list. - added interpolation on the gun kick motion, and ability to disable gun kick entirely (see cvar "v_gunkick") - disabled torches/bolts casting shadows - more content support - added support for per-entity alpha, and it works even without a custom progs.dat, works on static entities too, and both bsp and mdl models. Set values directly in the map and/or control it with quakec. When setting alpha, a value of "0" is interpreted as "default", which means 1.0 for most things, but for water polygons it t means obey the value of r_waterwarp. A value greater than 0, up to 1.0, will explicitly set the alpha, and override r_wateralpha for water polygons. A value of -1 will explictly set the alpha to 0 (invisible), and override r_wateralpha. (requires the new protocol, except for alpha -1, which makes things invisible even with protocol 15) - can playback protocol 15 demos containing the nonstandard U_TRANS bit, as recorded by nehahra, joequake, and aguirre's engine. When the server says it is running protocol 15, and the U_TRANS bit is encountered, fitzquake will assume it's the Nehahra protocol and parse it accordingly. - added support for -quoth command line switch. Loads quoth content regardless of current gamedir, and enables hipnotic statusbar layout. This allows you to load a mod that requires quoth, but is in a separate directory (i.e. fitzquake.exe -quoth -game warp) - fullbrights now use additive blending instead of alpha blending. This allows me to support external glowmaps, and entity transparency with fullbrights/glowmaps. In some cases, additive fullbrights are rendered using multitexture, but only if GL_EXT_texture_env_add is available. The command line option -nocombine will disable the use of GL_EXT_texture_env_add. - added support for external glowmaps (names must end in _luma or _glow) - added support for external liquid textures (name your files #water instead of *water) - added support for map-specific texture directories (put textures in /textures/mapname/) - interface improvements - improved crosshair accuracy somewhat for protocol 15, and improved it a lot in protocol 666 - rearranged scorebar so that map titles as long as 40 chars can be displayed without scrolling - statusbar displayed values now cap at 999 rather than displaying truncated numbers (1001 will be displayed as 999 instead of 001) - tab completion cycle order now alphabetized as a whole rather than grouped by type - added scr_conscale cvar (see below) - added scr_crosshairscale cvar (see below) - added scr_sbaralpha cvar (see below) - scr_showfps and scr_clock display now use same scale as console (scr_conscale, scr_conwidth) - video menu now shows aspect ratio of selected video mode - added aguirRe's trick of making the window perfectly cover the screen with no titlebar/borders, if you create a windowed mode with height/width equal to the desktop size. (not tested on dual monitors, though.) - developer features - added ability to monitor various stats that change dynamically, such as packet size, temp entities, and visedicts. (see cvar "devstats") - restricted spammy messages "packet overflow", "beam list overflow", and "too many efrags" to repeat at most once every 3 seconds - r_showbboxes now draws point entities too - "mcache" command now gives you a total number of models (note, this is a list of all loaded models, not just the current level's model precaches) - "soundlist" command now gives you a total number of sounds (note, this is a list of all loaded sounds, not just the current level's sound precaches) - "give" command can now give armor values above 200 - added imagedump command (see below) - "x is not a field" message is now shown only if developer = 1 - bugfixes - added Baker's fixes for Intel display adapters - fixed tab completion cycle never reaching certain commands/cvars in list - fixed -dinput mouse doesn't work after vid_restart - fixed rotated alias models incorrectly culled - fixed sky animation on brush models - fixed "invalid pixel format" error when switching between two video modes with the same bit depth, on certain chipsets (Baker had this problem) - fixed alt-tab fullscreen trashed window on some nvidia, intel cards (from Baker) - fixed some TGAs load upside down - fixed non-square PCX loading appears interlaced - fixed PCX loading from inside pakfiles appears as random noise - fixed player skin corruption bug (thanks aguirRe) - fixed improperly trying to colormap the playermodel before a map is loaded, after switching games (could cause a crash or discolored textures) - fixed too-dark fog on world/brushmodels with -nomtex - fixed overbright models too light with fog and -nocombine - fixed r_wateralpha support on brush entities - fixed grenade shadows spinning wildly instead of staying on the ground - fixed solid fogged sky was not quite the same color as solid fogged geometry, for certain colors of fog - fixed trigger_changelevel with missing map causes apparent hang - fixed hang when r_stereo and r_lightmap are both enabled - fixed "W_GetLumpinfo" crash when a graphic is missing from gfx.wad. Prints a console message instead. Missing graphics will be drawn as a checkerboard image. Note: conchars is the one graphic that must be in the gfx.wad, since the console won't even function without it. - fixed accidentally stripping -hipnotic and -rogue directories when switching games - fixed give command doesn't update currentammo - fixed changing gamedirs while a skybox is loaded sometimes corrupts textures/lightmaps in the next map loaded - fixed unnecessary creation of "glquake" subdirectory - fixed 0Hz/0bpp showing up in video menu sometimes - fixed -aliases triggered on alt-tab - fixed con_logcenterprint considering identical messages to be duplicates even though the map has changed in between - fixed hang in proxmap2, when going through one of the teleporters (thanks spirit, mh) - fixed lightning bolt memory corruption crash (rare) - source cleanup - removed all ASM code from source, and removed gas2masm project - cleaned up unnecessary library dependencies in source release - renamed local variable "errno" to fix a compiling problem on visual c++ express edition - added dxsdk folder to source release cvars: - devstats. default 0. If 1, prints various the current and peak values of various stats that change over time, such as packetsize, and edicts. Note: even if devstats is set to 0, fitzquake will keep track of peak values so when you turn it on, the peaks are accurate. Devstats display scale follows console text scale. - r_lerpmodels. default 0. If 1, do interpolation on model animations, with exceptions for torches (r_nolerp_list) & muzzleflares (interpolation is suspended for two frames if EF_MUZZLEFLASH is encountered, on the assumption a muzzleflare happens at the same time.) If 2, lerp all animations, without exception. If 0, disable interpolation (to mimic standard quake.) - r_lerpmove. default 0. If 1, do movement interpolation on MOVETYPE_STEP entities (i.e. monsters.) If 0, disable interpolation (to mimic standard quake.) I recommend that you use r_lerpmove and r_lerpmodels together, or turn them both off, otherwise monsters will move strangely. - r_nolerp_list. Contains a comma-separated list of filenames of models to exclude from lerping. Filename must include the relative path and extension, for example "progs/flame.mdl". The default is "progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl". This should include all torches in id1, quoth, and bastion, which look bad when lerped, and the zerstorer chainsaw and xmen fist, which also look bad lerped. - r_skyfog. default 0.5. Controls how much the sky is obscured by the fog. 0 = sky is completely unfogged, 1 = sky is completely fogged. - scr_conscale. default 1. Scales the console text larger, but only has an effect when scr_conwidth is 0. - scr_crosshairscale. default 1. Scales the crosshair larger. 1 = normal, 10 = maximum enlargement - scr_sbaralpha. default 1. Controls the transparency of the statusbar background. 0 = invisible, 1 = opaque (original quake behavior), in-between values give different levels of transparency. Pro tip: set it to 0.99 and it will still appear opaque, but the 3D view will expand to fill the area on both sides of the statusbar. - v_gunkick. default 1. If 1, standard quake view kick when you fire your gun. If 2, interpolates the view kick. If 0, disables view kick entirely. commands: - imagedump. Dumps all loaded textures from opengl into tga files. This shows the textures as they exist in opengl texture memory. Texture names containing '*' will be renamed with '#' instead. - sv_protocol. Sets the network protocol used by the server. Default is 666. Possible values are 15 (standard netquake protocol) or 666 (new fitzquake protocol.) Changes to the protocol will not take effect until the next time you load/reload a level. When running protocol 666, standard clients won't be able to connect to your server, and they won't be able to play any demos you record. When running protocol 15, only 256 models and 256 sounds can be sent to the client, which means you would see invisible entities and not hear some sounds, when running a map or mod that has more than 256 models or sounds. There is also some other data the server will suppress in protocol 15, such as per-entity alpha. Also note, dzip's special demo compression does not work on demos that use modified protocols, so you will get a compression ratio no better than standard zip compression. changes in 0.80 --------------- - map loading is about four times faster. This is due to some optimizations in the texture loading code. - video mode can now be changed in-game. You can change resolution, color depth, refresh rate, and switch between windowed and fullscreen modes. This can be accomplished easily using the video options menu, and is also available at the console using cvars. Note: if you launch fitzquake with -width, -height, -window, or -bpp in the command line, Fitzquake will use the command line settings and ignore whatever it reads from the config files at startup. However, you will still be able to change the video mode from the menu or the console as you like. Also note: to change video modes by execing a config file, the config file must include "vid_restart" after the other vid_ cvars have been set. (see cvars "vid_width," "vid_height," "vid_fullscreen," "vid_bpp," "vid_refreshrate," and commands "vid_restart," "vid_test") - added control of entity count limits (MAX_EDICTS.) The default maximum has been increased from 600 to 1024. It can be raised even higher (up to 8192 -- this is a limit set by the network protocol) using a cvar. (see cvar "max_edicts") - added control of vertical sync. (see cvar "vid_vsync") - added control of anistropic filtering. Anisotropic filtering is a method to improve texture clarity on surfaces when viewed at steep angles. (see cvar "gl_texture_anisotropy") - console buffer size can now be set. The command line option "-consize" allows you to specify the buffer size in kilobytes. For reference, fitzquake's default buffer size is 64k, and glquake's is 16k. 16k is also the smallest size fitzquake will allow you to set. Note: this buffer lives in the heap, so if you want to have a HUGE buffer, you might need to increase -heapsize also. - increased max surface extents from 256 (the software quake maximum) to 2000. For reference, the glquake maximum is 512. This should eliminate the "bad surface extents" crash when running some maps that could be played in glquake, but not fitzquake or winquake. - increased max vertices in an alias model from 1024 (the glquake maximum) to 2000 (the software quake maximum.) - increased MAX_CHANNELS from 128 to 512 and MAX_DYNAMIC_CHANNELS from 8 to 128 - screenshot filenames are now in the format "fitz0000.tga", increasing the maximum number of screenshots per folder from one hundred to ten thousand. - vid_describemodes output cleaned up; now displays a list of valid refresh rates for each mode - added a more intuitive cvar control of slow motion/fast-forward for demos and live gameplay. (see cvar "host_timescale") - "reset to defaults" option in the menu now executes the "resetall" command before loading default.cfg - game command now writes config.cfg to current gamedir before switching - +mlook is now saved to config.cfg - changed smallest allowed window size from 320x240 to 320x200 - console cursor images are now hard-coded, and the insert mode cursor is now a vertical bar instead of an underscore. This was prompted by several popular mods (OUM, Xmen TC) using nonstandard cursors, which are incompatible the fitzquake console enhancements. - gl_farclip now defaults to 16384. This should be high enough to handle even the largest open areas without unwanted clipping. The only reason you'd want to lower this number is if you see z-fighting. - added cvar r_drawworld (see below) - added cvar r_showtris (see below) - added cvar r_showbboxes (see below) - added a command to cycle a cvar through a list of values. (see command "cycle") - mapname command now works on dedicated server. - added a hack to fix those white edges on the bottom of the large box of shells. I feel dirty, but they look better, now. - changed stuffcmds behavior to allow hyphenated map names, config file names, etc. in the command line. (example: "fitzquake.exe +exec my-config.cfg +map my-map") However, you still can't load a map or config file when the first character in the filename is a hyphen. - skybox loader now reverts to scrolling sky if all 6 skybox faces failed to load. - tweaked circular particles to match the apparent size of the square particles. - fixed crash when loading mods with large player skins (like the chainsaw mod, and PerQuake.) Colormapping can now handle any size player texture (limited to the heapsize, of course.) - fixed bug where a replacement model in a mod is messed up becuase a matching .ms2 file in id1/glquake is present. The fix is simply to disable all mesh caching, which slows down model loading a little. - fixed freeze when gl_overbright is 1 and either texture_env_combine or multitexture is disabled or not supported. - fixed "numgltextures == MAX_GLTEXTURES" crash when viewing multiplayer->setup menu. - fixed "numgltextures == MAX_GLTEXTURES" crash when playing large maps (nesp09,) due to frequent model recaches. - fixed bug where entities and water were not being drawn any frame in which a model had to be recached. - fixed skybox texture showing up in the place of other textures/skins/lightmaps, when the previous loaded map had a skybox. - fixed missing polygons on edges of screen when underwater and r_waterwarp is 1. - fixed missing polygons on edges of screen when r_stereo is enabled. - fixed long mapnames that scroll are truncated to be shorter than what appears in the console. Well, sort of. What I did was increase the maximum length from 39 to 127. A mapname longer than 127 will still be truncated, but these are pretty rare. - fixed rogue's teamplay skin showing up as an all-white texture. - fixed checkerboard texture shows up sometimes when an animated texture has fullbright pixels on some frames, but not others (reactor core in junk.bsp) - fixed color 255 is not fullbright - fixed fuscia dots appearing in corners of resampled textures - fixed mapname command crashes when client is disconnected. - fixed cl_nolerp 1 screws up speed of demo playback - fixed annoying client-side step-up smoothing when in noclip mode (except on nonlocal servers.) - fixed scr_clock 2 displays hour twelve as "0" instead of "12" - fixed skip textured surfaces still drawn even after running tyrann's skip utility - fixed crash when loading a map with a sky texture where the "sky" in the texturename is not lowercase - fixed hang in e2m2 on easy skill, where you can shoot one of the buttons at the beginning and then trick-jump through the open gate. Now it prints a warning message ("SV_TouchLinks: null link") and lets you keep playing. - fixed bug when viewsize < 100, and r_oldwater is 0, where you can see the water textures overlaying part of the brown frame around the viewport. - fixed bug where imagelist and r_speeds2 would report the same megabyte counts in both 16bpp and 32bpp mode, even though texture bpp should match (and does match) framebuffer bpp. The numbers are now different and accurate for each bit depth. - removed cvars "vid_config_x," "vid_config_y," "vid_wait," "vid_nopageflip," "_vid_wait_override," "_vid_default_mode," "_vid_default_mode_win," and "vid_stretch_by_2," none of which glquake ever used. - removed cvar "vid_mode" and commands "vid_describemode" and "vid_nummodes," because of the new video mode handling. cvars: - gl_texture_anisotropy. Controls the amount of anisotropy in texture filtering. If 1 or less than 1, texture filtering is normal (isotropic.) If greater than 1, increasing degrees of anisotropic filtering are used, up to the hardware maximum. Set value to 2 for 2x anisotropic, 4 for 4x, etc. Default 1. - host_timescale. Scales the passage of time on client and server. Set to 0 or 1 for normal speed, less than 1 for slow motion, and greater than 1 for fast-forward. If greater than 0, overrides host_framerate. Default 0. - max_edicts. Sets the maximum number of entites on both the client and server. Default 1024. Acceptable values range from 256 to 8192. Set to 600 to mimic standard quake. Changes won't take effect until the next time a map is loaded. Note: if a client connects to a server, and the client's maximum is lower than the server's, the client will probably crash if it ever sees an entnum higher than its local max_edicts. Warning: you may need to increase -heapsize if you want a high max_edicts value. - r_drawworld. If 1, draw world as usual. If 0, don't draw the world. Default 1. (compare r_drawentities) - r_showbboxes. If 1, draw a wireframe bounding box around each entity. Note that these are the server-side per-edict physics bounding boxes, not the client-side per-model rendering bboxes. If 0, disable this feature. Default 0. - r_showtris. If 1, draw wireframe outlines for every triangle in the scene. Like in Quake 3, the lines will be visible even through solid geometry. If 2, draw the outlines only on visible surfaces (like r_showtris 2 in Medal of Honor.) If 0, disable wireframe overlay. Default 0. - vid_bpp. Sets the color depth of the screen in fullscreen mode. Windowed mode ignores this setting. Can be 16 or 32. Default 16. (Changes won't take effect until the next call to vid_restart.) - vid_fullscreen. If 1, fitzquake will run fullscreen. If 0, fitzquake will run in a window. Default 1. (Changes won't take effect until the next call to vid_restart.) - vid_height. Sets the vertical screen/window resolution. Default 480. In windowed mode, cannot be less than 200. (Changes won't take effect until the next call to vid_restart.) - vid_refreshrate. Sets the refresh rate of the screen in fullscreen mode. Windowed mode ignores this setting. Possible values include 60, 70, 72, 75, 85, etc. Default 60. (Changes won't take effect until the next call to vid_restart.) - vid_width. Sets the horizontal screen/window resolution. Default 640. In windowed mode, cannot be less than 320. (Changes won't take effect until the next call to vid_restart.) - vid_vsync. Set to 1 to enable vertical sync, which eliminates tearing, but caps your framerate at the monitor refreshrate. Set to 0 to disable vertical sync, which allows tearing but doesn't cap your framerate. Default 0. Note: If fitzquake detects that your driver settings have forced vsync to be disabled, it will post a message to the console saying so, and this cvar will have no effect. commands: - "cycle <cvar> <value> [<value> [<value> ...]]" to cycle a cvar through a list of values.. Note: this command will get stuck on a list that contains the same value more than once, such as "cycle blah 1 2 1 3". If you're doing anything that complex you can just use aliases. - vid_restart. Tries to set a video mode that matches the values of vid_width, vid_height, vid_fullscreen, and, if vid_fullscreen is 1, vid_bpp and vid_refreshrate. - vid_test. Like vid_restart, except that after switching to the new mode pops up a confirmation dialogue. This is useful if you are not sure what modes your monitor can handle, so you don't get stuck with a blank screen. The dialogue has a time limit so that if you don't press a key within 5 seconds, it will revert to the previous mode. changes in 0.75 --------------- - totally rewritten bsp drawing code. The new code combines the advantages of the gl_texsort 1 and gl_texsort 0 codepaths from glquake into one codepath that uses texture sorting and multitexture. In my tests, i've found that it's about the same speed as glquake in low poly scenes (like the original quake levels,) but as you get into the thousands of wpolys, it's faster and faster. - 2x overbright lighting. Lighting now looks like software quake. Just like overbright lighting on models, overbright on world polys requires GL_EXT_texture_env_combine (TNT and later, voodoo4 and later.) Without it, FitzQuake will be use two passes to render overbright world polys. So if you don't have that extension, you might disable it for performance reasons. (see cvar "gl_overbright") - colored lighting support using .lit files. - totally new water surface animation. The new method requires no surface subdivision, isn't plagued by tearing and sparklies caused by tjunctions, and looks almost identical to software quake's water, and doesn't slow down on very large sheets of water. (see cvars "r_waterquality" and "r_oldwater") - old water aninmation fixed so that it doesn't look bad when gl_subdivide_size is 32 or lower. - can load external textures (currently targa and pcx) if they match the texture name in the bsp and are located in the id1/textures, or <MODDIR>/textures directory. At the moment no other images (skins, menu, etc.) can be replaced. - gamma correction now goes back to normal when Fitzquake loses focus. - tab completion now adds a space after the completed command/cvar if the cursor is at the end of the editline. - increased the max length of the video mode list from 30 to 80. This should alleviate the problems people with newer cards were having trying to use some 32-bit modes -- there were so many 16-bit modes that they filled up the list before all 32-bit modes could be detected. The video menu will still only list a certain number of modes due to space constraints, but you can see the complete list by using the console command "vid_describemodes" - number of listed video modes in the "video options" menu increased from 27 to 36. - added alpha control for the front sky layer. (see cvar "r_skyalpha") - clock can now display time in 24-hour or "military" time. - added an "mtex" counter to the r_speeds 2 readout. This measures the number of megabytes of texture memory used each frame to draw the scene. Note: this doesn't count textures used to draw the console, menu, or statusbar. - added optional drawing of surfaces inside sky leaves, for compiler/map testing purposes. (see cvar "r_oldskyleaf") - sky surfaces on bmodels are now visible, though drawn incorrectly. - fixed multiple textures in bsp with same name or no name get overwritten/not loaded. (example: rd1m3) - fixed some nasty texture loading bugs that were especially hounding 3dfx users (wrong texture, no texture, or unnecessarily low-res textures displayed on models and world.) These bugs would also occur in conjunction with nonzero values of gl_max_size or gl_picmip. - fixed bug where changing gl_max_size or gl_picmip in-game would screw up alias model texture coordinates. - fixed bug where if -gamma is specified at the command line, the "gamma" cvar would be ignored. - fixed model more than 2048 units above floor us unlit by static lighting. - fixed crash with con_logcenterprint when centerprint message was too long. - fixed crash when changing to a nonexistant gamedir and then trying to write a file (screenshot, etc.) Fitzquake now creates the directory as needed. - fixed "bad surface extents" error when sky or water surface is missing from bsp file. - fixed alias model shadows write to z-buffer. - fixed underwater intermission camera has warp, but no screenblend. - fixed console buffer still scrolled back after using the "clear" command. - fixed console command history (the list of previous commands) not being rewound after toggling the console. - removed cvar gl_texsort. New bsp drawing code always sorts by texture. - removed cvar gl_ztrick. The depth buffer is now cleared every frame. - removed cvar gl_keeptjunctions. Extra verts created by qbsp to eliminate tjunctions are now always kept. - removed "sliding on monsters' heads" fix, becuase I decided I don't like the idea of changing gameplay, even if the original behaviour is clearly a bug. Since this bug can be fixed in quakec also, I feel safer leaving it as it was. cvars: - gl_overbright. default 1. This variable controls overbright lighting on the world polygons. (For lighting on models, use gl_overbright_models.) If 1, overbright will be enabled and lighting will resemble software Quake. If 0, overbright will be disabled and lighting will resemble GLQuake. - r_oldskyleaf. default 0. If 0, surfaces inside sky leaves will be skipped by the renderer. If 1, they will be drawn whenever they are in your PVS, just like any other surface. - r_oldwater. default 1. If 1, use the old GLQuake method of subdividing the water surface to enable a warping animation. If 0, use the new render-to-texture method. Note: in general, r_oldwater 0 looks better and runs slower. So experiment to see if the performance hit is acceptable to you. - r_skyalpha. default 1. Sets the alpha of the front sky layer. Note that if sky alpha is less than 1.0, the sky will be drawn in two passes even if you have multitexture. - r_waterquality. default 8. Sets the quality of the water when r_oldwater is 0. Can be anywhere from 1 to 64. Lower values give better performance, higher values look better. A value of 4 will provide water that looks at least as good as glquake can get, and 32 is close enough to software quake for all but the most picky. To control the quality of water when r_oldwater is 1, use gl_subdivide_size instead. - scr_clock. default 0. If 1, game time is displayed. If 2, system time is displayed in 12-hour format. If 3, system time will be displayed in 24-hour or "military" time. Changes in 0.70 --------------- - added anaglyph stereo rendering. Note that this will cut your framerate in half, as it is rendering the scene once for each eye. You might want to turn off r_drawviewmodel as it is hard to focus on becuase it is so close. (see cvars "r_stereo", "r_stereodepth") - now uses ARB_multitexture if present, otherwise tries to use SGIS_multitexture. This should fix various blending bugs on some cards, such as weird cloud layers, all-black models, and inverted torches. (only ARB guarantees that GL_DECAL blending will work) - overbright models now uses GL_EXT_texture_env_combine if supported (TNT and later, voodoo4 and later,) which saves one or two passes on model rendering when gl_overbright_models is 1. The command line option -nocombine will disable this. - gl_overbright_models now defaults to 1 - custom palettes are now correctly loaded when you use the "game" command. - RecursiveLightPoint is now lerped for smoother lighting of slow-moving models. Check out the ogre in e3m3 for an example. - dynamic lighting (rockets, etc) has been moderately sped up. (some lightmaps were being uploaded even though they weren't actually touched by a dynamic light.) - overhauled 2d drawing to allow independent scaling of console, menu, and sbar (see cvars "scr_conwdith," "scr_menuscale," and "scr_sbarscale") command line switches "-conwidth" and "-conheight" removed. cvar "scr_stretch_menus" removed. - user control of max framerate. (see cvar "host_maxfps") - improved the accuracy of the FPS counter a bit, but it still seems suspect. - particles can now be drawn as quads or triangles. (see cvar "r_quadparticles") - opengl information (vendor, renderer, version, extensions) is no longer printed during initialization. (see command "gl_info") - rewrote texture management. Now instead of quake's memory usage going up and up forever (becuase textures were uploaded to the opengl.dll and never freed,) all textures will get flushed when you switch games, bringing you back down to where you were when fitzquake first launched. - gl_texturemode command will now accept a number (1 through 6) as well as the name (gl_linear_mipmap_nearest, etc.) - gl_describetexturemodes will list all texturemodes. - the inside of sky leaves are no longer rendered -- so when noclipping inside them, it will look the same as noclipping inside a solid wall. This does not affect gameplay. - cleaned up intermission display in singleplayer -- no more overlapping numbers - r_speeds readout modified a bit. (see cvar "r_speeds") - r_sky_quality now defaults to 12 instead of 8, since skies are now drawn in 1 pass (with multitexture at least) - gl_texsort now always defaults to 0. (it used to be forced to 1 when multitexture was unavailable) - fixed bug where models would actually darken when dlights got bright enough - fixed deathmatch, coop cvars not reset to zero when starting a new game from the single player menu - fixed r_lightmap doesn't work when gl_texsort = 0. - fixed inverted lightmaps / no textures / no dynamic light bug when multitexture is disabled and gl_texsort = 0 - fixed scrolling map title in wrong place when width does not equal conwidth - fixed a few color borking problems in 16-bit mode. The front sky layer, sprites, and pics with transparency will still look a bit off (as in glquake,) but at least the console image and statusbar background look better. Though it isn't perfect, it should once again look like what you expect from glquake in 16bit. - fixed pixel gap on both sides of the console in 1024x768 - fixed wpoly count being slightly lower when gl_texsort = 0 (the count was correct when gl_texsort = 1) - fixed lmap count always zero when gl_texsort = 1 - dlight fans are now drawn after water, so that it looks right at least when wateralpha is 1. - fixed a possible bug with older 3dfx cards (voodoo 1/2/rush) where the gamma cvar might not work (untested) - fixed old commands showing up in the console prompt after hitting 'enter' - increased MAX_HANDLES so that you should never see the "out of handles" error message. - removed cvar "chase_alpha." the transparent player model was buggy and didn't work well in a lot of conditions. - removed cvar "gl_doubleeys" (yes, that is the correct misspelling) With overbright models, eyes can be seen as easily as in software mode. - removed cvars "cl_crossx," "cl_crossy," "lcd_x," "lcd_yaw," and "gl_reporttjunctions" which didn't do anything (in glquake, at least). - removed support for GL_EXT_shared_texture_palette (special 8-bit texture format) - removed VCR code. command line switches "-record" and "-playback" no longer supported. - removed support for command line switch "-gamma" -- just use the gamma cvar, or idgamma or something. cvars: - r_stereo. default 0. If nonzero, the scene will be rendered once in red, and again in cyan, with the two views shifted slightly. If you have 3D glasses you can appreciate this (assumes that the left eye is red and the right eye is cyan.) The value of r_stereo sets the eye separation. If your glasses have red on the right eye, use a negative value to flip the views. - r_stereodepth. default 128. Sets the distance at which the two views will converge when stereo rendering is active. - scr_conwdith. default 0. Sets the virtual console width, where smaller numbers means larger text. Values larger than window width, or smaller than 320, will be clamped to that range, and all values will be rounded to a multiple of 8. If 0, the window width will be used. Note that values that divide evenly into the window width will make the text look nicest. - scr_menuscale. default 1. Sets the scale factor for menus and other centered overlays. If 1, images will be drawn at 1:1 scale. If 2, images will be double size. Menus will never be drawn smaller than 1:1, and never larger than the size of the window. Note that integer values will make the text look nicest. - scr_sbarscale. default 1. Sets the scale factor for the statusbar. If 1, images will be drawn at 1:1 scale. If 2, images will be double size. The statusbar will never be drawn smaller than 1:1, and never larger than the width of the window. Note that integer values will make the text look nicest. - host_maxfps. default 72. sets the maximum frames per second fitzquake will render (also the maximum number of server frames per second.) Clamped to the range 10 - 1000. Set to 72 to mimic standard quake. - r_quadparticles. default 1. If 1, particles are drawn as GL_QUADS instead of GL_TRIANGLES. Quads use 4 verts instead of 3, but the fillrate cost is 1/2 that of triangles. Depending on your card, either one may be faster. This cvar has no effect on the appearance of particles. - r_speeds. default 0. Values of 1 and 2 will give you increasing amounts of information. When you see two numbers separated by a slash, the first number is polys, and the second number is passes. commands: - gl_info. Displays opengl info which was previously displayed during initialization: vendor, renderer, version, and extensions - imagelist. Displays a list of loaded textures, and their dimentions. - gl_texturemode. Now accepts a number (1 through 6) as well as the name (gl_nearest, etc.) - gl_describetexturemodes. Lists all texturemodes. Changes in 0.65 --------------- - gamma cvar now supported. (see cvar "gamma") - fullbrights on models now supported. - odd-sized world textures are now bilinearly resampled (instead of glquake's nearest pixel resample) - removed all fixed-size buffers for loading textures; now the only limit is the size of your memory heap (textures will still be downsampled if they are bigger than the hardware can handle) - styled lights (torch flicker, etc.) can now be disabled (see cvar "r_flatlightstyles") - sky now uses multitexture if available. - centerprints are now optionally logged to the console (see cvar "con_logcenterprint") - number of savegame slots increased to 20 (from 12) - if a map title is longer than 22 characters, it scrolls marquee-style in the statusbar. - gl_flashblend defaults to 1 again. (consistency with glquake) - gl_ztrick defaults to 1 again. (consistency with glquake) - command line gamma now defaults to 1.0 for all cards. (consistency with glquake, plus hardware gamma is better) - now checks hardware for maximum texture size. Users of later voodoo cards should be able to see large textures now. (see cvar "gl_max_size") - now shows AM/PM when scr_clock is 2 - fixed crash when starting dedicated server - fixed crash when loading too many textures. (now it throws a sys_error and quits) - fixed fitzquake-specific crash when player goes near water in a demo playback. - scr_conalpha now actually works. - keypad enter in the console works again. - optional 2x overbrightening on models. (see cvar "gl_overbright_models") - optional quake2-style noclip. (see cvar "sv_altnoclip") - new icon cvars: - con_logcenterprint: If 1, centerprint messages will be logged to the console in sp/coop. If 2, they will also be logged in deathmatch. Default 1. - gamma: Brighten or darken the screen to compensate for differences between monitors. This is now supported by using your video card's gamma support. Just like in winquake, values less than 1 are brighter and values greater than one are darker. Default 1. Notes: I have added special code so that this will work on 3dfx cards too, but i have no way to check that it works. If fitzquake crashes, your hardware gamma may be stuck at the wrong value. You can use the "display settings" control panel fix this, or you could try lordhavoc's useful "setgamma" utility (available on this page.) Also note that if texture-brightening gamma has been requested at the command line (fitzquake.exe -gamma ), harware gamma will not be used and the gamma cvar will have no effect. - gl_max_size: Now defaults to 0. If 0, textures will be as large as the hardware allows. Positive values can be used to impose a limit smaller than the hardware's reported maximum. - gl_overbright_models: If 1, models will be rendered using 2x overbrightening and will appear at roughly the same brightness as they do in software quake, which is noticably brighter than the default fitzquake / glquake appearance. I disabled this cvar by default becuase this is still a poorly supported feature -- it currently takes 2 or 3 passes to render a model when this feature is enabled, compared to only 1 pass when it is disabled. Default 0. - r_flatlightstyles: If 1, styled lights (torch flicker, etc.) will be displayed as a steady light. If 2, the peak intensity will be used instead of the average intensity. Default 0. - sv_altnoclip: If 1, enable the alternative noclip movement which resembles quake2 and is not constrained to the horizontal plane. Set to 0 to retain quake's original noclip behavior. Default 1. Changes in 0.60 --------------- - graphics: - better sky projection, configurable for performance - menus and other overlays are now centered on the screen, and can optionally stretch to fit resolution. - all 2d graphics now obey gl_texturemode and all texturemode changes take effect immediately - underwater warping now resembles quake3's perspective munging, and obeys r_waterwarp - fixed frustum culling b0rked (giving HOM at certain FOV / vidsize / screensize combinations) - fixed lack of support for VP_PARALLEL_ORIENTED, VP_PARALLEL_UPRIGHT, and FACING_UPRIGHT sprites - fixed fullbrights not displayed on world/bmodels - fixed texture cache mismatch error - fixed pink edges on sprites, menu items, etc - fixed particle z-buffer bug (apparent when a particle is in front of a water surface) - fixed ugly resampling of non-power of two gfx, skins, sprites - fixed large models (shamblers, shub) dissapearing near edge of screen - fixed statusbar not visible when gl_clear = 1 - fixed r_fullbright change not immedate when gl_texsort = 0 - fixed alias models still dark when r_fullbright = 1 - fixed HOM when screen is partially underwater - fixed gunshot decals not showing up on some walls - sky and water warp now freeze when you pause, as well as lightning bolts - r_novis changes now take effect immediately, rather than when you cross a leaf boundary - removed mirror code - two particle styles, circle and square (cvar controlled) - console: - improved tab completion: - hitting tab once will display a list of possible matches and complete the line using the first match - hitting tab or shift-tab will cycle through the matches - autocomplete will now match against aliases as well as commands and cvars. - autocomplete will now complete later in the string (e.g. "bind mouse1 +att" + tab will complete '+attack') - autocomplete will even complete inside the string (e.g. "bind m +attack" + tab will complete 'mouse1' if the cursor is right after the 'm') - new key functionality: - tab -- autocomplete, cycle through multiple matches - shift-tab -- cycle backwards through multiple matches - ins -- toggle insertmode - del -- delete current character - backspace -- delete previous character - ctrl-v -- paste from windows clippboard - leftarrow -- move cursor one character left in line - rightarrow -- move cursor one character right in line. or, get one character from the previous command. - home -- move cursor to beginning of line - end -- move cursor to end of line - ctrl-pgup -- scroll up a screen at a time - ctrl-pgdn -- scroll down a screen at a time - ctrl-home -- scroll to top of console history - ctrl-end -- scroll to bottom of console history - carets indicate that you are scrolled back, like in quakeworld/quake2 - left arrow, right arrow, pgup, pgdn keys now auto-repeat - quadrupled the length of the console history - commands: - "game <gamedir>" to load a mod. - "reset <cvar>" to reset a cvar to default. Note that this is the engine default, not the default.cfg value - resetall. resets all cvars. - mods. lists all child folders of quake directory which contain either a progs.dat or a pak file - maps. lists all addon levels available (i.e. all levels that are not in id1/*.pak) - mapname. outputs the short name of the current level (e.g. "e1m5") - cmdlist. alphabetized. 'cmdlist blah' will list only cmds that start with 'blah' - cvarlist. alphabetized. 'cvarlist blah' will list only cvars that start with 'blah' - "inc <cvar> [amount]" to increment a cvar by amount. amount defaults to 1. - "toggle <cvar>" to invert the value of a cvar (nonzero -> 0 and 0 -> 1) - god, noclip, notarget, and fly can now be explicitly set. example: "god 0" will disable god mode - viewpos. outputs (X,Y,Z) pitch yaw roll - "give a <value>" now gives you armour. type depends on value - bindlist. lists all key bindings - "alias <name>" now outputs the current command string - "unalias <name>" to delete an alias - unaliasall. delete all aliases. - condump. dumps console to condump.txt - fog. set global fog. syntax is "fog <density>", "fog <red> <green> <blue>", or "fog <density> <red> <green> <blue>" See section on modding for details. Set density to 0 to disable fog. - "sky <skyname>" to load a skybox. if skyname is "", this will turn off skybox rendering. - stuffcmds now parses the "cmdline" cvar rather than the args actually passed to the program. This is useful for loading mods dynamically, so you can edit the cmdline before execing quake.rc (which calls "stuffcmds") - cvars: - scr_stretch_menus. default 1. if 1, menus and other overlays are stretched to fill the screen - scr_conalpha. default 1. This is the opacity when the console is halfscreen. 0.6 will mimic glquake - scr_clock. default 0. if 1, game time is displayed. If 2, system time is displayed. - scr_showfps. default 0. if 1, FPS are displayed. - r_waterwarp recognized. default 1. if zero, no underwater warping will take place - r_drawflat recognized. default 0. if 1, polygons will be drawn as a solid color with no lightmap or texture - r_particles. default 1. 0 = no particles, 1 = circular particles, 2 = square particles - r_fastsky. default 0. if 1, sky will be rendered as solid color, for added performance - r_sky_quality. default 8. Higher number divides the sky more, for a smoother effect and slower performance. - r_clearcolor now supported. default 2. specify a palette index from 0 to 255. - gl_fullbrights. default 1. set to 0 to disable fullbrights - gl_farclip. default 8192. set to 4096 to mimic glquake. note that the skybox will be drawn somewhat closer than this value. - cl_maxpitch. default 90 (straight down.) set to 80 to mimic normal quake - cl_minpitch. default -90 (straight up.) set to -70 to mimic normal quake - cl_keypad. default 1. if 0, keypad keys will respond as in quake.exe (for example, pushing 'KP_END' will be the same as pushing '1') - gl_flashblend now defaults to 0. - gl_ztrick now defaults to 0. - gl_keeptjunctions now defaults to 1. (note, contrary to the name of this cvar, what is being kept is the extra polygon verts which *eliminate* tjunctions. This is a good thing, so i made it default to 1) - chase_alpha. default 1. lower values make the chasecam player model translucent. Buggy. - keyboard - keypad keys are now bindable: KP_NUMLOCK, KP_SLASH, KP_STAR, KP_MINUS, KP_HOME, KP_UPARROW, KP_PGUP, KP_PLUS, KP_LEFTARROW, KP_5, KP_RIGHTARROW, KP_END, KP_DOWNARROW, KP_PGDN, KP_ENTER, KP_INS, KP_DEL - command line: - running with -gamma at the command line will set the gamma. There is still no way to change this value in game. Default is 1.0 for 3dfx cards, 0.7 for all others - if unspecified, -conwidth now defaults to -width - modding extensions: - skyboxes (worldspawn and qc settable), currently only targa and pcx formats accepted - global fog (worldspawn and qc settable) - physics - fixed sliding around while standing on solid entities' bounding boxes (monsters, players, etc) - misc - default heapsize is now 32mb (was 16mb) - default zonesize is now 256k (was 48k) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/fitzquake080.txt�������������������������������������������������������������0000644�0000000�0000000�00000112172�11364571402�016347� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ================================================================================ Fitzquake version 0.80, May 26, 2005 Filename : fitzquake080.exe Author : John Fitzgibbons Email Address : johnfitz@u.washington.edu Author's Homepage : http://www.celephais.net/ Fitzquake Homepage : http://www.celephais.net/fitzquake Fitzquake is a modified glquake based on the source code released by id Software. My primary focus is fixing a lot of the rendering bugs which made glquake inferior to the software renderer. My secondary focus is adding conveniences for mappers and general users. I am also slowly adding support for new modding or mapping features such as skyboxes, fog, and colored light. While I have made extensive changes to the code, I pretty much use the same OpenGL features that the original glquake uses. Therefore, if you can run glquake, you can probably run Fitzquake. I am not finished working on this project, so bug reports and feature requests are welcome. Acknowlegements -------------------------------------------------------------------------------- id Software (quake and quake2 code) LordHavoc (code and assistance) Bengt Jardrup (feedback, assistance, testing) additional thanks to: Aardappel, SmallPileOfGibs, FrikaC, Vondur, Topaz, Tomaz, Tonik, Radix, EvilTypeGuy, NightBringer, MH, Maddes, Fett, Craig Wills, Heffo, Riot, Gleeb, people in #flipcode, and others for their tutorials, code, testing, and assistance. Copyright / Permissions -------------------------------------------------------------------------------- Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. History ================================================================================ changes in 0.80 --------------- - map loading is about four times faster. This is due to some optimizations in the texture loading code. - video mode can now be changed in-game. You can change resolution, color depth, refresh rate, and switch between windowed and fullscreen modes. This can be accomplished easily using the video options menu, and is also available at the console using cvars. Note: if you launch fitzquake with -width, -height, -window, or -bpp in the command line, Fitzquake will use the command line settings and ignore whatever it reads from the config files at startup. However, you will still be able to change the video mode from the menu or the console as you like. Also note: to change video modes by execing a config file, the config file must include "vid_restart" after the other vid_ cvars have been set. (see cvars "vid_width," "vid_height," "vid_fullscreen," "vid_bpp," "vid_refreshrate," and commands "vid_restart," "vid_test") - added control of entity count limits (MAX_EDICTS.) The default maximum has been increased from 600 to 1024. It can be raised even higher (up to 8192 -- this is a limit set by the network protocol) using a cvar. (see cvar "max_edicts") - added control of vertical sync. (see cvar "vid_vsync") - added control of anistropic filtering. Anisotropic filtering is a method to improve texture clarity on surfaces when viewed at steep angles. (see cvar "gl_texture_anisotropy") - console buffer size can now be set. The command line option "-consize" allows you to specify the buffer size in kilobytes. For reference, fitzquake's default buffer size is 64k, and glquake's is 16k. 16k is also the smallest size fitzquake will allow you to set. Note: this buffer lives in the heap, so if you want to have a HUGE buffer, you might need to increase -heapsize also. - increased max surface extents from 256 (the software quake maximum) to 2000. For reference, the glquake maximum is 512. This should eliminate the "bad surface extents" crash when running some maps that could be played in glquake, but not fitzquake or winquake. - increased max vertices in an alias model from 1024 (the glquake maximum) to 2000 (the software quake maximum.) - increased MAX_CHANNELS from 128 to 512 and MAX_DYNAMIC_CHANNELS from 8 to 128 - screenshot filenames are now in the format "fitz0000.tga", increasing the maximum number of screenshots per folder from one hundred to ten thousand. - vid_describemodes output cleaned up; now displays a list of valid refresh rates for each mode - added a more intuitive cvar control of slow motion/fast-forward for demos and live gameplay. (see cvar "host_timescale") - "reset to defaults" option in the menu now executes the "resetall" command before loading default.cfg - game command now writes config.cfg to current gamedir before switching - +mlook is now saved to config.cfg - changed smallest allowed window size from 320x240 to 320x200 - console cursor images are now hard-coded, and the insert mode cursor is now a vertical bar instead of an underscore. This was prompted by several popular mods (OUM, Xmen TC) using nonstandard cursors, which are incompatible the fitzquake console enhancements. - gl_farclip now defaults to 16384. This should be high enough to handle even the largest open areas without unwanted clipping. The only reason you'd want to lower this number is if you see z-fighting. - added cvar r_drawworld (see below) - added cvar r_showtris (see below) - added cvar r_showbboxes (see below) - added a command to cycle a cvar through a list of values. (see command "cycle") - mapname command now works on dedicated server. - added a hack to fix those white edges on the bottom of the large box of shells. I feel dirty, but they look better, now. - changed stuffcmds behavior to allow hyphenated map names, config file names, etc. in the command line. (example: "fitzquake.exe +exec my-config.cfg +map my-map") However, you still can't load a map or config file when the first character in the filename is a hyphen. - skybox loader now reverts to scrolling sky if all 6 skybox faces failed to load. - tweaked circular particles to match the apparent size of the square particles. - fixed crash when loading mods with large player skins (like the chainsaw mod, and PerQuake.) Colormapping can now handle any size player texture (limited to the heapsize, of course.) - fixed bug where a replacement model in a mod is messed up becuase a matching .ms2 file in id1/glquake is present. The fix is simply to disable all mesh caching, which slows down model loading a little. - fixed freeze when gl_overbright is 1 and either texture_env_combine or multitexture is disabled or not supported. - fixed "numgltextures == MAX_GLTEXTURES" crash when viewing multiplayer->setup menu. - fixed "numgltextures == MAX_GLTEXTURES" crash when playing large maps (nesp09,) due to frequent model recaches. - fixed bug where entities and water were not being drawn any frame in which a model had to be recached. - fixed skybox texture showing up in the place of other textures/skins/lightmaps, when the previous loaded map had a skybox. - fixed missing polygons on edges of screen when underwater and r_waterwarp is 1. - fixed missing polygons on edges of screen when r_stereo is enabled. - fixed long mapnames that scroll are truncated to be shorter than what appears in the console. Well, sort of. What I did was increase the maximum length from 39 to 127. A mapname longer than 127 will still be truncated, but these are pretty rare. - fixed rogue's teamplay skin showing up as an all-white texture. - fixed checkerboard texture shows up sometimes when an animated texture has fullbright pixels on some frames, but not others (reactor core in junk.bsp) - fixed color 255 is not fullbright - fixed fuscia dots appearing in corners of resampled textures - fixed mapname command crashes when client is disconnected. - fixed cl_nolerp 1 screws up speed of demo playback - fixed annoying client-side step-up smoothing when in noclip mode (except on nonlocal servers.) - fixed scr_clock 2 displays hour twelve as "0" instead of "12" - fixed skip textured surfaces still drawn even after running tyrann's skip utility - fixed crash when loading a map with a sky texture where the "sky" in the texturename is not lowercase - fixed hang in e2m2 on easy skill, where you can shoot one of the buttons at the beginning and then trick-jump through the open gate. Now it prints a warning message ("SV_TouchLinks: null link") and lets you keep playing. - fixed bug when viewsize < 100, and r_oldwater is 0, where you can see the water textures overlaying part of the brown frame around the viewport. - fixed bug where imagelist and r_speeds2 would report the same megabyte counts in both 16bpp and 32bpp mode, even though texture bpp should match (and does match) framebuffer bpp. The numbers are now different and accurate for each bit depth. - removed cvars "vid_config_x," "vid_config_y," "vid_wait," "vid_nopageflip," "_vid_wait_override," "_vid_default_mode," "_vid_default_mode_win," and "vid_stretch_by_2," none of which glquake ever used. - removed cvar "vid_mode" and commands "vid_describemode" and "vid_nummodes," because of the new video mode handling. cvars: - gl_texture_anisotropy. Controls the amount of anisotropy in texture filtering. If 1 or less than 1, texture filtering is normal (isotropic.) If greater than 1, increasing degrees of anisotropic filtering are used, up to the hardware maximum. Set value to 2 for 2x anisotropic, 4 for 4x, etc. Default 1. - host_timescale. Scales the passage of time on client and server. Set to 0 or 1 for normal speed, less than 1 for slow motion, and greater than 1 for fast-forward. If greater than 0, overrides host_framerate. Default 0. - max_edicts. Sets the maximum number of entites on both the client and server. Default 1024. Acceptable values range from 256 to 8192. Set to 600 to mimic standard quake. Changes won't take effect until the next time a map is loaded. Note: if a client connects to a server, and the client's maximum is lower than the server's, the client will probably crash if it ever sees an entnum higher than its local max_edicts. Warning: you may need to increase -heapsize if you want a high max_edicts value. - r_drawworld. If 1, draw world as usual. If 0, don't draw the world. Default 1. (compare r_drawentities) - r_showbboxes. If 1, draw a wireframe bounding box around each entity. Note that these are the server-side per-edict physics bounding boxes, not the client-side per-model rendering bboxes. If 0, disable this feature. Default 0. - r_showtris. If 1, draw wireframe outlines for every triangle in the scene. Like in Quake 3, the lines will be visible even through solid geometry. If 2, draw the outlines only on visible surfaces (like r_showtris 2 in Medal of Honor.) If 0, disable wireframe overlay. Default 0. - vid_bpp. Sets the color depth of the screen in fullscreen mode. Windowed mode ignores this setting. Can be 16 or 32. Default 16. (Changes won't take effect until the next call to vid_restart.) - vid_fullscreen. If 1, fitzquake will run fullscreen. If 0, fitzquake will run in a window. Default 1. (Changes won't take effect until the next call to vid_restart.) - vid_height. Sets the vertical screen/window resolution. Default 480. In windowed mode, cannot be less than 200. (Changes won't take effect until the next call to vid_restart.) - vid_refreshrate. Sets the refresh rate of the screen in fullscreen mode. Windowed mode ignores this setting. Possible values include 60, 70, 72, 75, 85, etc. Default 60. (Changes won't take effect until the next call to vid_restart.) - vid_width. Sets the horizontal screen/window resolution. Default 640. In windowed mode, cannot be less than 320. (Changes won't take effect until the next call to vid_restart.) - vid_vsync. Set to 1 to enable vertical sync, which eliminates tearing, but caps your framerate at the monitor refreshrate. Set to 0 to disable vertical sync, which allows tearing but doesn't cap your framerate. Default 0. Note: If fitzquake detects that your driver settings have forced vsync to be disabled, it will post a message to the console saying so, and this cvar will have no effect. commands: - "cycle <cvar> <value> [<value> [<value> ...]]" to cycle a cvar through a list of values.. Note: this command will get stuck on a list that contains the same value more than once, such as "cycle blah 1 2 1 3". If you're doing anything that complex you can just use aliases. - vid_restart. Tries to set a video mode that matches the values of vid_width, vid_height, vid_fullscreen, and, if vid_fullscreen is 1, vid_bpp and vid_refreshrate. - vid_test. Like vid_restart, except that after switching to the new mode pops up a confirmation dialogue. This is useful if you are not sure what modes your monitor can handle, so you don't get stuck with a blank screen. The dialogue has a time limit so that if you don't press a key within 5 seconds, it will revert to the previous mode. changes in 0.75 --------------- - totally rewritten bsp drawing code. The new code combines the advantages of the gl_texsort 1 and gl_texsort 0 codepaths from glquake into one codepath that uses texture sorting and multitexture. In my tests, i've found that it's about the same speed as glquake in low poly scenes (like the original quake levels,) but as you get into the thousands of wpolys, it's faster and faster. - 2x overbright lighting. Lighting now looks like software quake. Just like overbright lighting on models, overbright on world polys requires GL_EXT_texture_env_combine (TNT and later, voodoo4 and later.) Without it, FitzQuake will be use two passes to render overbright world polys. So if you don't have that extension, you might disable it for performance reasons. (see cvar "gl_overbright") - colored lighting support using .lit files. - totally new water surface animation. The new method requires no surface subdivision, isn't plagued by tearing and sparklies caused by tjunctions, and looks almost identical to software quake's water, and doesn't slow down on very large sheets of water. (see cvars "r_waterquality" and "r_oldwater") - old water aninmation fixed so that it doesn't look bad when gl_subdivide_size is 32 or lower. - can load external textures (currently targa and pcx) if they match the texture name in the bsp and are located in the id1/textures, or <MODDIR>/textures directory. At the moment no other images (skins, menu, etc.) can be replaced. - gamma correction now goes back to normal when Fitzquake loses focus. - tab completion now adds a space after the completed command/cvar if the cursor is at the end of the editline. - increased the max length of the video mode list from 30 to 80. This should alleviate the problems people with newer cards were having trying to use some 32-bit modes -- there were so many 16-bit modes that they filled up the list before all 32-bit modes could be detected. The video menu will still only list a certain number of modes due to space constraints, but you can see the complete list by using the console command "vid_describemodes" - number of listed video modes in the "video options" menu increased from 27 to 36. - added alpha control for the front sky layer. (see cvar "r_skyalpha") - clock can now display time in 24-hour or "military" time. - added an "mtex" counter to the r_speeds 2 readout. This measures the number of megabytes of texture memory used each frame to draw the scene. Note: this doesn't count textures used to draw the console, menu, or statusbar. - added optional drawing of surfaces inside sky leaves, for compiler/map testing purposes. (see cvar "r_oldskyleaf") - sky surfaces on bmodels are now visible, though drawn incorrectly. - fixed multiple textures in bsp with same name or no name get overwritten/not loaded. (example: rd1m3) - fixed some nasty texture loading bugs that were especially hounding 3dfx users (wrong texture, no texture, or unnecessarily low-res textures displayed on models and world.) These bugs would also occur in conjunction with nonzero values of gl_max_size or gl_picmip. - fixed bug where changing gl_max_size or gl_picmip in-game would screw up alias model texture coordinates. - fixed bug where if -gamma is specified at the command line, the "gamma" cvar would be ignored. - fixed model more than 2048 units above floor us unlit by static lighting. - fixed crash with con_logcenterprint when centerprint message was too long. - fixed crash when changing to a nonexistant gamedir and then trying to write a file (screenshot, etc.) Fitzquake now creates the directory as needed. - fixed "bad surface extents" error when sky or water surface is missing from bsp file. - fixed alias model shadows write to z-buffer. - fixed underwater intermission camera has warp, but no screenblend. - fixed console buffer still scrolled back after using the "clear" command. - fixed console command history (the list of previous commands) not being rewound after toggling the console. - removed cvar gl_texsort. New bsp drawing code always sorts by texture. - removed cvar gl_ztrick. The depth buffer is now cleared every frame. - removed cvar gl_keeptjunctions. Extra verts created by qbsp to eliminate tjunctions are now always kept. - removed "sliding on monsters' heads" fix, becuase I decided I don't like the idea of changing gameplay, even if the original behaviour is clearly a bug. Since this bug can be fixed in quakec also, I feel safer leaving it as it was. cvars: - gl_overbright. default 1. This variable controls overbright lighting on the world polygons. (For lighting on models, use gl_overbright_models.) If 1, overbright will be enabled and lighting will resemble software Quake. If 0, overbright will be disabled and lighting will resemble GLQuake. - r_oldskyleaf. default 0. If 0, surfaces inside sky leaves will be skipped by the renderer. If 1, they will be drawn whenever they are in your PVS, just like any other surface. - r_oldwater. default 1. If 1, use the old GLQuake method of subdividing the water surface to enable a warping animation. If 0, use the new render-to-texture method. Note: in general, r_oldwater 0 looks better and runs slower. So experiment to see if the performance hit is acceptable to you. - r_skyalpha. default 1. Sets the alpha of the front sky layer. Note that if sky alpha is less than 1.0, the sky will be drawn in two passes even if you have multitexture. - r_waterquality. default 8. Sets the quality of the water when r_oldwater is 0. Can be anywhere from 1 to 64. Lower values give better performance, higher values look better. A value of 4 will provide water that looks at least as good as glquake can get, and 32 is close enough to software quake for all but the most picky. To control the quality of water when r_oldwater is 1, use gl_subdivide_size instead. - scr_clock. default 0. If 1, game time is displayed. If 2, system time is displayed in 12-hour format. If 3, system time will be displayed in 24-hour or "military" time. Changes in 0.70 --------------- - added anaglyph stereo rendering. Note that this will cut your framerate in half, as it is rendering the scene once for each eye. You might want to turn off r_drawviewmodel as it is hard to focus on becuase it is so close. (see cvars "r_stereo", "r_stereodepth") - now uses ARB_multitexture if present, otherwise tries to use SGIS_multitexture. This should fix various blending bugs on some cards, such as weird cloud layers, all-black models, and inverted torches. (only ARB guarantees that GL_DECAL blending will work) - overbright models now uses GL_EXT_texture_env_combine if supported (TNT and later, voodoo4 and later,) which saves one or two passes on model rendering when gl_overbright_models is 1. The command line option -nocombine will disable this. - gl_overbright_models now defaults to 1 - custom palettes are now correctly loaded when you use the "game" command. - RecursiveLightPoint is now lerped for smoother lighting of slow-moving models. Check out the ogre in e3m3 for an example. - dynamic lighting (rockets, etc) has been moderately sped up. (some lightmaps were being uploaded even though they weren't actually touched by a dynamic light.) - overhauled 2d drawing to allow independent scaling of console, menu, and sbar (see cvars "scr_conwdith," "scr_menuscale," and "scr_sbarscale") command line switches "-conwidth" and "-conheight" removed. cvar "scr_stretch_menus" removed. - user control of max framerate. (see cvar "host_maxfps") - improved the accuracy of the FPS counter a bit, but it still seems suspect. - particles can now be drawn as quads or triangles. (see cvar "r_quadparticles") - opengl information (vendor, renderer, version, extensions) is no longer printed during initialization. (see command "gl_info") - rewrote texture management. Now instead of quake's memory usage going up and up forever (becuase textures were uploaded to the opengl.dll and never freed,) all textures will get flushed when you switch games, bringing you back down to where you were when fitzquake first launched. - gl_texturemode command will now accept a number (1 through 6) as well as the name (gl_linear_mipmap_nearest, etc.) - gl_describetexturemodes will list all texturemodes. - the inside of sky leaves are no longer rendered -- so when noclipping inside them, it will look the same as noclipping inside a solid wall. This does not affect gameplay. - cleaned up intermission display in singleplayer -- no more overlapping numbers - r_speeds readout modified a bit. (see cvar "r_speeds") - r_sky_quality now defaults to 12 instead of 8, since skies are now drawn in 1 pass (with multitexture at least) - gl_texsort now always defaults to 0. (it used to be forced to 1 when multitexture was unavailable) - fixed bug where models would actually darken when dlights got bright enough - fixed deathmatch, coop cvars not reset to zero when starting a new game from the single player menu - fixed r_lightmap doesn't work when gl_texsort = 0. - fixed inverted lightmaps / no textures / no dynamic light bug when multitexture is disabled and gl_texsort = 0 - fixed scrolling map title in wrong place when width does not equal conwidth - fixed a few color borking problems in 16-bit mode. The front sky layer, sprites, and pics with transparency will still look a bit off (as in glquake,) but at least the console image and statusbar background look better. Though it isn't perfect, it should once again look like what you expect from glquake in 16bit. - fixed pixel gap on both sides of the console in 1024x768 - fixed wpoly count being slightly lower when gl_texsort = 0 (the count was correct when gl_texsort = 1) - fixed lmap count always zero when gl_texsort = 1 - dlight fans are now drawn after water, so that it looks right at least when wateralpha is 1. - fixed a possible bug with older 3dfx cards (voodoo 1/2/rush) where the gamma cvar might not work (untested) - fixed old commands showing up in the console prompt after hitting 'enter' - increased MAX_HANDLES so that you should never see the "out of handles" error message. - removed cvar "chase_alpha." the transparent player model was buggy and didn't work well in a lot of conditions. - removed cvar "gl_doubleeys" (yes, that is the correct misspelling) With overbright models, eyes can be seen as easily as in software mode. - removed cvars "cl_crossx," "cl_crossy," "lcd_x," "lcd_yaw," and "gl_reporttjunctions" which didn't do anything (in glquake, at least). - removed support for GL_EXT_shared_texture_palette (special 8-bit texture format) - removed VCR code. command line switches "-record" and "-playback" no longer supported. - removed support for command line switch "-gamma" -- just use the gamma cvar, or idgamma or something. cvars: - r_stereo. default 0. If nonzero, the scene will be rendered once in red, and again in cyan, with the two views shifted slightly. If you have 3D glasses you can appreciate this (assumes that the left eye is red and the right eye is cyan.) The value of r_stereo sets the eye separation. If your glasses have red on the right eye, use a negative value to flip the views. - r_stereodepth. default 128. Sets the distance at which the two views will converge when stereo rendering is active. - scr_conwdith. default 0. Sets the virtual console width, where smaller numbers means larger text. Values larger than window width, or smaller than 320, will be clamped to that range, and all values will be rounded to a multiple of 8. If 0, the window width will be used. Note that values that divide evenly into the window width will make the text look nicest. - scr_menuscale. default 1. Sets the scale factor for menus and other centered overlays. If 1, images will be drawn at 1:1 scale. If 2, images will be double size. Menus will never be drawn smaller than 1:1, and never larger than the size of the window. Note that integer values will make the text look nicest. - scr_sbarscale. default 1. Sets the scale factor for the statusbar. If 1, images will be drawn at 1:1 scale. If 2, images will be double size. The statusbar will never be drawn smaller than 1:1, and never larger than the width of the window. Note that integer values will make the text look nicest. - host_maxfps. default 72. sets the maximum frames per second fitzquake will render (also the maximum number of server frames per second.) Clamped to the range 10 - 1000. Set to 72 to mimic standard quake. - r_quadparticles. default 1. If 1, particles are drawn as GL_QUADS instead of GL_TRIANGLES. Quads use 4 verts instead of 3, but the fillrate cost is 1/2 that of triangles. Depending on your card, either one may be faster. This cvar has no effect on the appearance of particles. - r_speeds. default 0. Values of 1 and 2 will give you increasing amounts of information. When you see two numbers separated by a slash, the first number is polys, and the second number is passes. commands: - gl_info. Displays opengl info which was previously displayed during initialization: vendor, renderer, version, and extensions - imagelist. Displays a list of loaded textures, and their dimentions. - gl_texturemode. Now accepts a number (1 through 6) as well as the name (gl_nearest, etc.) - gl_describetexturemodes. Lists all texturemodes. Changes in 0.65 --------------- - gamma cvar now supported. (see cvar "gamma") - fullbrights on models now supported. - odd-sized world textures are now bilinearly resampled (instead of glquake's nearest pixel resample) - removed all fixed-size buffers for loading textures; now the only limit is the size of your memory heap (textures will still be downsampled if they are bigger than the hardware can handle) - styled lights (torch flicker, etc.) can now be disabled (see cvar "r_flatlightstyles") - sky now uses multitexture if available. - centerprints are now optionally logged to the console (see cvar "con_logcenterprint") - number of savegame slots increased to 20 (from 12) - if a map title is longer than 22 characters, it scrolls marquee-style in the statusbar. - gl_flashblend defaults to 1 again. (consistency with glquake) - gl_ztrick defaults to 1 again. (consistency with glquake) - command line gamma now defaults to 1.0 for all cards. (consistency with glquake, plus hardware gamma is better) - now checks hardware for maximum texture size. Users of later voodoo cards should be able to see large textures now. (see cvar "gl_max_size") - now shows AM/PM when scr_clock is 2 - fixed crash when starting dedicated server - fixed crash when loading too many textures. (now it throws a sys_error and quits) - fixed fitzquake-specific crash when player goes near water in a demo playback. - scr_conalpha now actually works. - keypad enter in the console works again. - optional 2x overbrightening on models. (see cvar "gl_overbright_models") - optional quake2-style noclip. (see cvar "sv_altnoclip") - new icon cvars: - con_logcenterprint: If 1, centerprint messages will be logged to the console in sp/coop. If 2, they will also be logged in deathmatch. Default 1. - gamma: Brighten or darken the screen to compensate for differences between monitors. This is now supported by using your video card's gamma support. Just like in winquake, values less than 1 are brighter and values greater than one are darker. Default 1. Notes: I have added special code so that this will work on 3dfx cards too, but i have no way to check that it works. If fitzquake crashes, your hardware gamma may be stuck at the wrong value. You can use the "display settings" control panel fix this, or you could try lordhavoc's useful "setgamma" utility (available on this page.) Also note that if texture-brightening gamma has been requested at the command line (fitzquake.exe -gamma ), harware gamma will not be used and the gamma cvar will have no effect. - gl_max_size: Now defaults to 0. If 0, textures will be as large as the hardware allows. Positive values can be used to impose a limit smaller than the hardware's reported maximum. - gl_overbright_models: If 1, models will be rendered using 2x overbrightening and will appear at roughly the same brightness as they do in software quake, which is noticably brighter than the default fitzquake / glquake appearance. I disabled this cvar by default becuase this is still a poorly supported feature -- it currently takes 2 or 3 passes to render a model when this feature is enabled, compared to only 1 pass when it is disabled. Default 0. - r_flatlightstyles: If 1, styled lights (torch flicker, etc.) will be displayed as a steady light. If 2, the peak intensity will be used instead of the average intensity. Default 0. - sv_altnoclip: If 1, enable the alternative noclip movement which resembles quake2 and is not constrained to the horizontal plane. Set to 0 to retain quake's original noclip behavior. Default 1. Changes in 0.60 --------------- - graphics: - better sky projection, configurable for performance - menus and other overlays are now centered on the screen, and can optionally stretch to fit resolution. - all 2d graphics now obey gl_texturemode and all texturemode changes take effect immediately - underwater warping now resembles quake3's perspective munging, and obeys r_waterwarp - fixed frustum culling b0rked (giving HOM at certain FOV / vidsize / screensize combinations) - fixed lack of support for VP_PARALLEL_ORIENTED, VP_PARALLEL_UPRIGHT, and FACING_UPRIGHT sprites - fixed fullbrights not displayed on world/bmodels - fixed texture cache mismatch error - fixed pink edges on sprites, menu items, etc - fixed particle z-buffer bug (apparent when a particle is in front of a water surface) - fixed ugly resampling of non-power of two gfx, skins, sprites - fixed large models (shamblers, shub) dissapearing near edge of screen - fixed statusbar not visible when gl_clear = 1 - fixed r_fullbright change not immedate when gl_texsort = 0 - fixed alias models still dark when r_fullbright = 1 - fixed HOM when screen is partially underwater - fixed gunshot decals not showing up on some walls - sky and water warp now freeze when you pause, as well as lightning bolts - r_novis changes now take effect immediately, rather than when you cross a leaf boundary - removed mirror code - two particle styles, circle and square (cvar controlled) - console: - improved tab completion: - hitting tab once will display a list of possible matches and complete the line using the first match - hitting tab or shift-tab will cycle through the matches - autocomplete will now match against aliases as well as commands and cvars. - autocomplete will now complete later in the string (e.g. "bind mouse1 +att" + tab will complete '+attack') - autocomplete will even complete inside the string (e.g. "bind m +attack" + tab will complete 'mouse1' if the cursor is right after the 'm') - new key functionality: - tab -- autocomplete, cycle through multiple matches - shift-tab -- cycle backwards through multiple matches - ins -- toggle insertmode - del -- delete current character - backspace -- delete previous character - ctrl-v -- paste from windows clippboard - leftarrow -- move cursor one character left in line - rightarrow -- move cursor one character right in line. or, get one character from the previous command. - home -- move cursor to beginning of line - end -- move cursor to end of line - ctrl-pgup -- scroll up a screen at a time - ctrl-pgdn -- scroll down a screen at a time - ctrl-home -- scroll to top of console history - ctrl-end -- scroll to bottom of console history - carets indicate that you are scrolled back, like in quakeworld/quake2 - left arrow, right arrow, pgup, pgdn keys now auto-repeat - quadrupled the length of the console history - commands: - "game <gamedir>" to load a mod. - "reset <cvar>" to reset a cvar to default. Note that this is the engine default, not the default.cfg value - resetall. resets all cvars. - mods. lists all child folders of quake directory which contain either a progs.dat or a pak file - maps. lists all addon levels available (i.e. all levels that are not in id1/*.pak) - mapname. outputs the short name of the current level (e.g. "e1m5") - cmdlist. alphabetized. 'cmdlist blah' will list only cmds that start with 'blah' - cvarlist. alphabetized. 'cvarlist blah' will list only cvars that start with 'blah' - "inc <cvar> [amount]" to increment a cvar by amount. amount defaults to 1. - "toggle <cvar>" to invert the value of a cvar (nonzero -> 0 and 0 -> 1) - god, noclip, notarget, and fly can now be explicitly set. example: "god 0" will disable god mode - viewpos. outputs (X,Y,Z) pitch yaw roll - "give a <value>" now gives you armour. type depends on value - bindlist. lists all key bindings - "alias <name>" now outputs the current command string - "unalias <name>" to delete an alias - unaliasall. delete all aliases. - condump. dumps console to condump.txt - fog. set global fog. syntax is "fog <density>", "fog <red> <green> <blue>", or "fog <density> <red> <green> <blue>" See section on modding for details. Set density to 0 to disable fog. - "sky <skyname>" to load a skybox. if skyname is "", this will turn off skybox rendering. - stuffcmds now parses the "cmdline" cvar rather than the args actually passed to the program. This is useful for loading mods dynamically, so you can edit the cmdline before execing quake.rc (which calls "stuffcmds") - cvars: - scr_stretch_menus. default 1. if 1, menus and other overlays are stretched to fill the screen - scr_conalpha. default 1. This is the opacity when the console is halfscreen. 0.6 will mimic glquake - scr_clock. default 0. if 1, game time is displayed. If 2, system time is displayed. - scr_showfps. default 0. if 1, FPS are displayed. - r_waterwarp recognized. default 1. if zero, no underwater warping will take place - r_drawflat recognized. default 0. if 1, polygons will be drawn as a solid color with no lightmap or texture - r_particles. default 1. 0 = no particles, 1 = circular particles, 2 = square particles - r_fastsky. default 0. if 1, sky will be rendered as solid color, for added performance - r_sky_quality. default 8. Higher number divides the sky more, for a smoother effect and slower performance. - r_clearcolor now supported. default 2. specify a palette index from 0 to 255. - gl_fullbrights. default 1. set to 0 to disable fullbrights - gl_farclip. default 8192. set to 4096 to mimic glquake. note that the skybox will be drawn somewhat closer than this value. - cl_maxpitch. default 90 (straight down.) set to 80 to mimic normal quake - cl_minpitch. default -90 (straight up.) set to -70 to mimic normal quake - cl_keypad. default 1. if 0, keypad keys will respond as in quake.exe (for example, pushing 'KP_END' will be the same as pushing '1') - gl_flashblend now defaults to 0. - gl_ztrick now defaults to 0. - gl_keeptjunctions now defaults to 1. (note, contrary to the name of this cvar, what is being kept is the extra polygon verts which *eliminate* tjunctions. This is a good thing, so i made it default to 1) - chase_alpha. default 1. lower values make the chasecam player model translucent. Buggy. - keyboard - keypad keys are now bindable: KP_NUMLOCK, KP_SLASH, KP_STAR, KP_MINUS, KP_HOME, KP_UPARROW, KP_PGUP, KP_PLUS, KP_LEFTARROW, KP_5, KP_RIGHTARROW, KP_END, KP_DOWNARROW, KP_PGDN, KP_ENTER, KP_INS, KP_DEL - command line: - running with -gamma at the command line will set the gamma. There is still no way to change this value in game. Default is 1.0 for 3dfx cards, 0.7 for all others - if unspecified, -conwidth now defaults to -width - modding extensions: - skyboxes (worldspawn and qc settable), currently only targa and pcx formats accepted - global fog (worldspawn and qc settable) - physics - fixed sliding around while standing on solid entities' bounding boxes (monsters, players, etc) - misc - default heapsize is now 32mb (was 16mb) - default zonesize is now 256k (was 48k) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/systest.c��������������������������������������������������������������������0000644�0000000�0000000�00000016163�11643523122�015234� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * stupid test tool that reports the type sizes and * their alignment offsets in structures, and the byte * order as detected at runtime and compile time. */ /* * endianness stuff: <sys/types.h> is supposed * to succeed in locating the correct endian.h * this BSD style may not work everywhere. */ #undef ENDIAN_GUESSED_SAFE #undef ENDIAN_ASSUMED_UNSAFE #include <sys/types.h> #include <stddef.h> #include <limits.h> #include <stdio.h> /* include more if it didn't work: */ #if !defined(BYTE_ORDER) # if defined(__linux__) || defined(__linux) # include <endian.h> # elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) # include <machine/endian.h> # elif defined(__sun) || defined(__svr4__) # include <sys/byteorder.h> # elif defined(_AIX) # include <sys/machine.h> # elif defined(sgi) # include <sys/endian.h> # elif defined(__DJGPP__) # include <machine/endian.h> # endif #endif /* endian includes */ #if defined(__BYTE_ORDER) && !defined(BYTE_ORDER) #define BYTE_ORDER __BYTE_ORDER #endif /* __BYTE_ORDER */ #if !defined(PDP_ENDIAN) #if defined(__PDP_ENDIAN) #define PDP_ENDIAN __PDP_ENDIAN #else #define PDP_ENDIAN 3412 #endif #endif /* NUXI endian (not supported) */ #if defined(__LITTLE_ENDIAN) && !defined(LITTLE_ENDIAN) #define LITTLE_ENDIAN __LITTLE_ENDIAN #endif /* __LITTLE_ENDIAN */ #if defined(__BIG_ENDIAN) && !defined(BIG_ENDIAN) #define BIG_ENDIAN __BIG_ENDIAN #endif /* __LITTLE_ENDIAN */ #if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) # if (BYTE_ORDER != LITTLE_ENDIAN) && (BYTE_ORDER != BIG_ENDIAN) # error "Unsupported endianness." # endif #else /* one of the definitions is mising. */ # undef BYTE_ORDER # undef LITTLE_ENDIAN # undef BIG_ENDIAN # undef PDP_ENDIAN # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # define PDP_ENDIAN 3412 #endif /* byte order defs */ #if !defined(BYTE_ORDER) /* supposedly safe assumptions: these may actually * be OS dependant and listing all possible compiler * macros here is impossible (the ones here are gcc * flags, mostly.) so, proceed carefully.. */ # if defined(__DJGPP__) || defined(MSDOS) || defined(__MSDOS__) # define BYTE_ORDER LITTLE_ENDIAN /* DOS */ # elif defined(__sun) || defined(__svr4__) /* solaris */ # if defined(_LITTLE_ENDIAN) /* x86 */ # define BYTE_ORDER LITTLE_ENDIAN # elif defined(_BIG_ENDIAN) /* sparc */ # define BYTE_ORDER BIG_ENDIAN # endif # elif defined(__i386) || defined(__i386__) || defined(__386__) || defined(_M_IX86) # define BYTE_ORDER LITTLE_ENDIAN /* any x86 */ # elif defined(__amd64) || defined(__x86_64__) || defined(_M_X64) # define BYTE_ORDER LITTLE_ENDIAN /* any x64 */ # elif defined(_M_IA64) # define BYTE_ORDER LITTLE_ENDIAN /* ia64 / Visual C */ # elif defined (__ppc__) || defined(__POWERPC__) || defined(_M_PPC) # define BYTE_ORDER BIG_ENDIAN /* PPC: big endian */ # elif (defined(__alpha__) || defined(__alpha)) || defined(_M_ALPHA) # define BYTE_ORDER LITTLE_ENDIAN /* should be safe */ # elif defined(_WIN32) || defined(_WIN64) /* windows : */ # define BYTE_ORDER LITTLE_ENDIAN /* should be safe */ # elif defined(__hppa) || defined(__hppa__) || defined(__sparc) || defined(__sparc__) /* others: check! */ # define BYTE_ORDER BIG_ENDIAN # endif # if defined(BYTE_ORDER) /* raise a flag, just in case: */ # define ENDIAN_GUESSED_SAFE BYTE_ORDER # endif #endif /* supposedly safe assumptions */ #if !defined(BYTE_ORDER) /* brain-dead fallback: default to little endian. * change if necessary!!!! */ # define BYTE_ORDER LITTLE_ENDIAN # define ENDIAN_ASSUMED_UNSAFE BYTE_ORDER #endif /* fallback. */ #if defined(ENDIAN_ASSUMED_UNSAFE) /* # if (ENDIAN_ASSUMED_UNSAFE == LITTLE_ENDIAN) # warning "Cannot determine endianess. Using LIL endian as an UNSAFE default" # elif (ENDIAN_ASSUMED_UNSAFE == PDP_ENDIAN) # warning "Cannot determine endianess. Using PDP (NUXI) as an UNSAFE default." # elif (ENDIAN_ASSUMED_UNSAFE == BIG_ENDIAN) # warning "Cannot determine endianess. Using BIG endian as an UNSAFE default." # endif */ #endif /* ENDIAN_ASSUMED_UNSAFE */ #define COMPILED_BYTEORDER BYTE_ORDER #include <stdio.h> #include <stdlib.h> int DetectByteorder (void) { int i = 0x12345678; /* U N I X */ /* BE_ORDER: 12 34 56 78 U N I X LE_ORDER: 78 56 34 12 X I N U PDP_ORDER: 34 12 78 56 N U X I */ if ( *(char *)&i == 0x12 ) return BIG_ENDIAN; else if ( *(char *)&i == 0x78 ) return LITTLE_ENDIAN; else if ( *(char *)&i == 0x34 ) return PDP_ENDIAN; return -1; } struct align_test_char { char dummy; char test; }; struct align_test_short { char dummy; short test; }; struct align_test_int { char dummy; int test; }; struct align_test_long { char dummy; long test; }; struct align_test_longlong { char dummy; long long test; }; struct align_test_float { char dummy; float test; }; struct align_test_double { char dummy; double test; }; struct align_test_longdouble { char dummy; long double test;}; struct align_test_voidptr { char dummy; void *test; }; int main (void) { int tmp = ((char) -1); printf ("char is signed type : %s - char is %s\n", (tmp < 0) ? "yes" : "no", (tmp < 0) ? "SIGNED" : "UNSIGNED"); printf ("Type sizes and alignment within structures:\n"); printf ("char : %d, packing offset: %d\n", (int) sizeof(char), (int) ((size_t) &((struct align_test_char *)0)->test)); printf ("short : %d, packing offset: %d\n", (int) sizeof(short), (int) ((size_t) &((struct align_test_short *)0)->test)); printf ("int : %d, packing offset: %d\n", (int) sizeof(int), (int) ((size_t) &((struct align_test_int *)0)->test)); printf ("long : %d, packing offset: %d\n", (int) sizeof(long), (int) ((size_t) &((struct align_test_long *)0)->test)); printf ("long long : %d, packing offset: %d\n", (int) sizeof(long long),(int) ((size_t) &((struct align_test_longlong *)0)->test)); printf ("void *ptr : %d, packing offset: %d\n", (int) sizeof(void *), (int) ((size_t) &((struct align_test_voidptr *)0)->test)); printf ("float : %d, packing offset: %d\n", (int) sizeof(float), (int) ((size_t) &((struct align_test_float *)0)->test)); printf ("double : %d, packing offset: %d\n", (int) sizeof(double), (int) ((size_t) &((struct align_test_double *)0)->test)); printf ("long double: %d, packing offset: %d\n", (int) sizeof(long double),(int)((size_t)&((struct align_test_longdouble *)0)->test)); printf ("ENDIANNESS (BYTE ORDER):\n"); tmp = DetectByteorder(); printf ("Runtime detection : "); switch (tmp) { case BIG_ENDIAN: printf ("Big Endian"); break; case LITTLE_ENDIAN: printf ("Little Endian"); break; case PDP_ENDIAN: printf ("PDP (NUXI) Endian"); break; default: printf ("Unknown Endian"); break; } printf ("\n"); tmp = COMPILED_BYTEORDER; printf ("Compile time detection: "); switch (tmp) { case BIG_ENDIAN: printf ("Big Endian"); break; case LITTLE_ENDIAN: printf ("Little Endian"); break; case PDP_ENDIAN: printf ("PDP (NUXI) Endian"); break; default: printf ("Unknown Endian"); break; } #if defined(ENDIAN_GUESSED_SAFE) printf (" (Safe guess)"); #elif defined(ENDIAN_ASSUMED_UNSAFE) printf (" (Unsafe assumption)"); #endif printf ("\n"); return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/QuakeSpasm_512.png�����������������������������������������������������������0000644�0000000�0000000�00000143665�12027635624�016541� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������ôxÔú�� �IDATxÚì½yœeWußû[ûœs皺»ªGu·º5¢ !²À̘Ù8 ãg<ãÇÆñ�þ8q ácÇ/ö‹_ ‰c^ÀŽƒñ#˜`cl3  , $¤–z®î®î®éÞs‡sö^ï}æ{ouµººêv÷úÖç¨îX­Ï:çì5ì5�‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ! BJ£Qßàå�Þ ày� @øÀÿ™]n5›")A �AöíœùaÇu^ç8Î^¿Õ™""Â7�|ôÐìÜ}"!aÊÿ™�¾  ‘}]¥K¥ÑÆ,1ø£¾ß~HL@6€z­v/$ð˜ñ�¯UPrÈ^ÝÑÎ࿬zÞ;;<{B$' â–ëöÌ<ylîa"ÚR\Ì Ø0�1sà*õo‰è—šÍ§D‚‚�‚pñÿ�þÀ­�ƒAd×dðÖÉqô$Òü�  ‹Í¿í´Û/ ƒxÆ5W=rðø™g(e—Ef†1 ¢t™Ì\[Ì�yJ1�¸®ó‡ó‹KÿX¤(ˆ Gñ¿À;<?UïL B¥äa¼Z†aF²^³=ºaˆ¿E"<¿Õò¿,Ò²lÙ4±«ä¹‡›mP¤ñ��p÷M{aŒ5cöô"ƒA ž'àw�üöc'‘ª0ê(0âJß©Õj/©×j�po¬Û6Rô €èœ–îψT…"­vïÖù%Æ0im µÉ)GQt(hm  GŸ1`Ãd¯1šð�½ý;·¾uÿέžHVe\0ÂÊÿ`¼·rêÓSN¡Ç¯§fAl}‰ˆ’Ï3ãÙ"Y¡Ï@$šöÞd£ŠëvM'—›6¦/* µFzÅ�| À‡¶o™ü\7 óìBóˆHY@ÎA­ZÝKDeƽL9/žrV@ôjÑé7̘›o&ïY# 2 8ÍÌpþ ¨"‚á¬qY¸âÑÖ“µMã<"ÚY)•~²R*ýäD­öq�¿ùÔñS‹¨1�a°×ÿÿ0óÛ�Ô@ýQ}f†6&Vî�Geþ¡ˆ¢ýþ4™K)1„-Rp�o« ¹QÕòðH¾Ý0�ÙtÔØÊŒ ³ç­�ÞxõŽ™‡˜ùUgç¤EØp$ P Å_¯¿šÿ/'c'?*»Ê)r"ÂónÚ mìJ»Üîâ»g£÷ó^[ü"[#‰é¥Vó9"macúƒ›Æj·¥ž>P)y({.&ÕÜg 3:Ý�A¨1¿ìÃu”J.Y­:¡µ)þqðJ;³ô¦^·óI‘º �እѨMôUf\°B6ŸۻgfjƒHÿCë$Üš ¤Ê?YxÂωąaÌŒ7î Œ>JD[°ë8435–3>³¿Ož].$r� L6JŸÃÅDp\W}¢äÕÿÀ=Íf‹Eú‚�¦üë?ð¿®Ã¾<~ŠŒ�›„5ÀzT¡6 ZuKlPüúR³y¿H]Æã'Ã=Û§¯ã·�¼ '¾†âÒ@"ÂÜ|ÍvÕZ9—`¢+-k´2TzíÞ `±Ñ¨ÿL³Ùúc9Âz#e€ÂF(þz£QÀ�’E–ŠõûÈ,¤Ú˜èàü¾Uá;Ìöóñö- /·ZÉ çâÐìÜò¡sÿìЉ9×uÔ[œM®'‹M*À&¯à‰ò{ªDÏus‡ë88µÔÊÚ �o4꟭×kâ b�—µò3€c�nŽõs¬Á9ΡJ2ú¬ ׯ ð£lòŸ£(5vÏ?^©Á EïjùþÏŠä…óåÑCÇÿøKß~lóR³ó†ƒÇÏÜðøY:xü,7ýn¡ÕdÞXeæ\£ […b{ œ\l¦ù)éGÀ+ˆèHµZ}£H^X/$ PXjµš àÌüË(VòB�ÙõQá97îE/Ð 2ökÌèiƒo}ÿ(”"8ÙV­éß™ñÚvÛÿ¬H_X öl›~l3ªifF¹Rb•±@™Šg+ºÝ�Æ0N/µf X=.¶Ž›jmˆˆþÀ;}ßo‰Ô‰�—ºò¯ø*€_&"& ŠGº ÚßÕ’‡;®Û)ÿTÅ+¥ ”‚Hƒ6Ùx Àu¢ü…µäЉ¹¿°ÀO¼w�éu¬ˆ %å¨Ù£¨üãçÆ0Œí(ÈÌücø€W*¿A¤.H@¸”•ÿ�_ŠN>Ÿk®RrqóÕÛÓ5 ÌŒ'ÏXhµã¶€ñVÂ3>ìûþ¯ˆä…‹É®éÍ•j½ü¿”R/a 9è…Ô 5ZÝ^Ò¥"nBÚŽ: šl•ohÀ03ÿ;Rô/ÍÎ-‹Ô‰�—’ò¿ÀÔ\ÖÇ+€m¨B¤òÞ©¸ÑJÜó7n½º_”¿°;Óq]÷åÌ|€NT%À*š`£TÔß50ïñ'G|Ol™¨cÓX• 'ó~Àã{¶O?K¤.H@¸À/øMf¶Ô¸¯•Ñìt†^†D„’ëô½î(m Î.û]"ú€´Zþ×EòÂF±{ë–?�ð®ÀøÝáƒ�C­AD‰ÇŸ…™±u²a·Àbs™­›ÆÌØ¿sæwëÒ¯ýÅìŠÄ1�„QTþ/ðY��ümSƒØ ¾òZî@/)6�ª¥¤ k6‚ð(3ÿÖ‘¹…O°{"uaDŒ€«zZ«Ý ·X}ž´xz@Œfìß1M†Ùg6w|ùÁï?*.ÙÖJñï¯Õjàó‘ò›¢LfA;¿žgÙOßàçì?4;wãá§?.Ê_%Ÿ<}dn±µÀ¿·ö+qjî!âÃDc„‹Êßn‡ d•xÿd ØQ¨¹Žó×?ÿö[Dâ‚D�„ ç¦kwÿò£sR…Ò¦xŠÚÖ‰¸àÇ3léÓ �VDT)y �^vhvNºø — ãc/gæOkc<G)µºÖflŸKrb¨ÐQ¨Zö°uÓŽŸ^ÂáSóñ½Ñ!¢}ß?$Ò$ lFýNžYúú÷13 ÌØlæ®}«Ó-ÌúKß®•JTñ¼‡˜y·(áRcqiù¯ÚÝ`gµä~¥ì9„sľ’)”amEd;.4¡HÁQŠˆ¨ àë•Je»H[€°®Ôk5wÛ–ñ??~jñÕPѠݬWcÛ&ý«^&Ðîö�¢bm  Z©ôè¡s7Ф…KéM¿ßêï¶ÞŽîNŸÏ-5‘…à ×q¢{+¹mà8êøîmS·>òø‘³"iA"�ºÀÌ_œ[|5)Zum¿íÏŸ†9)šöGýFé·+ž'eOÂeÁÜÙÅ à…·!&)€”-}UÈJ%Ê?L#�p•ÚjóðõûvîI .*ÕZm†€OpO´ ´�ŒaìØ2‘NDcF©ZØöD?pdŽê›ÊÀG;íöÿ!’.7jµÚu�þ€ëQè‹a ƒ…E©¹ r÷ÒŠFÉsyfS tà |ÍÁcsŸI b�Cùß àËT² XÑ�°Óû×ìÚÍ…¹)Dp•“GOA)�ñàWµ|ÿ‹¤…ËØ(3óŸ�x=rð2¸°0«4nÀ™›izÓ67pÃÞ]Ql2JÑ?ö_|¿HZX Žˆ@XåÂõÏðgd¯™\ä¾hEöïÚ mLægPÔ+Ì8pl.ir”çô-^Öòý¯Š¤…Ë™ t†ÿcód½].9/í…š£®–ı9@v+ ¹ËL¬òã™Ö ¨UKPаmó\lj;¾à–ëöÜöŠ{žõ_}ðÑ@$.H@¸ êõÚ'Àø‘h "Nr–û1ÌØ·s3ŒáLy'«3ãðìYVIº3þ;€où>‹¤…+‰íÓ“Ï\lu¿ED”­�ÌE�ŒÕ+˜«E17^½ Zuàß~âÈìÙ…åÖµ8*ÉÂP$ PXIñïª×kø‘xÒ“]¥œÌ4¾ÜA* l²-Ùþ‡@ t@xMË÷ß.Ê_¸™[xˆ¶øzìŒ1§‰~v+Í@³6&ɧa¶C¯yø]Ã̼ À±gìßõ&‘´0 WD ¢\.oð$�/JD¢X‡Sf´i„Ñbg.2ˆÁßÑ­–oDÒ•L«åŸpW½^û0~*kx®‹Ó“Q¼Ív 40 ¦¡¸(ŒßeüöïºúÑG?$Ò,ׂ纽;ˆÍc§vªB™Ÿíð§†��zZÃDI€Ùµ)oú®Çž:þa$;›‚ �ÀøXã‡�|†™a SÉu±uz<³ïO`vLOa¢QG­R‚ãäÓ¸¥ðÀã„ÐÚ þ¢1æÍÎý¤HY€0”gß²âì’ÿ3ÇÚ;INâ•bŽQdŸ™ms"4Û]œ<³ÌQG“cÝ^ø˜ð>‘² ô³´ÜüìøXãVG©ÏìÛ¹i·ap/ÔT¼ë*¥ÆêÕÔ WiN®R„ÅeÊ¡¸‘PÜ…ð{¶OWæ[­·--É–› €0€V§÷õãs‹[ÈÎ6·+EÿˆBÿ»÷P´O‰¨É07ßdÇ4 ÀÁ„M‘° ¬h<<³eê&mø�^NÔ(3ÕßJ9p½ ´Ï‰l5�(›ªK0~´ìº;�ü HZ�$ Pˆ¸fߎÚÍ×^õ3_·%ç(59>ìJB™¥"™Båh+òO|ß½ïû¢üaœ:=ß|øñï`æßJ•w4 PÇã(ûX)¡FjôB±QžöÚ¤8ð‚™ÍÿQ¤,H@H/—?àæÐhv"-!YÅΰ ~j¥$ÀÔM!��ø1‘® œ?<qä7®¿zçQ"|�/µ:´°ÜF§¢^-#Ô|.cœr7d”`È?;½i¼6wvI:n^áH# +œ;ž±ÏÙ1=õy"z±aCóËíh$iሖ’¸²²�ÐÆÀpn¶Ï߸Û÷%Ó_ž.g–¿¹ej⬣Ô+ƒPs·R­R‚ç:0†Á”Æãâßa/˜ Tº[G�:Aˆj¹„FµÂ•Jù™3›ÆçOÏ/]¤,€p…²czê¿xm¼†hc°�²óL™ít²øÐ‘æOZû�g�<Ç÷ýŽHX.ŒÓóKßhwÂ뺽ðV¸V)QÉsì˜íÈ�Èv ƒ�õMÚn÷Œ7ª¨”Jä:ᇶn™üΩ3‹Š”¯L¤ ð fûôÔŸz®ûÆl°pÙïZ…ž!~Ó0ƒÙ ok íhÎ̘%Âí¾ïŸ ÂÚ1V¯Ñ0ß»e²AZ¡6¹@¯€�´:Ýdן”K˜õjl¥’míaØ0Ì|Û##à Dr�®P¦7Mü~¨ÍCÝËe‡Ú$^Šﬢqd‘ÆÏì0££^57a ¹þêmÿ¸× 1Ì¥$)7c}[÷ŸÌà਷ÖÌŒR©”™Îi@v’g‰ˆ¾×¨•·5ýîI‘ò•…T\™ÊÿS�ý¼½ÿ‰˜³;…yÅ_Ü_LLê{ÑáŽVËP$,kÏxÂ0¿‰½mÝüSg—0;·€v¯‡vDo2Êžƒ’«2ý;¸ïþŽ_lÔ*2ˆK �áræµ÷Þîm™ÿ @¯Evœ/3:½�^0°‡¿1ŒP›hfyfÙ`» ±µ ~Ô÷ýáâñðã‡ïcæC&¨ Ð& Ñ@K=g¦ ¡HíÛµuÓ}7ï¹Jò® äd_I'ÛuÿªÕ龜(ßÞ·ê\fÑÐ&›È-0$EDx½ïûŸ ÂÅgîìÒß´{zÛb³ýì¥fÇ&(¹N΀÷ܨ˜7Ú¦«WÊÉýoëi£±Üôá8»ÊÙÝ ƒÝ‹MÿS"e1�„Ë„÷ìô&Çêe´yÉ¢ßÖ†´6ÐÚXÏž­—o¸x˜h¨R*9 §=Ɖè_ù¾ÿŸDÊ‚°~ôz½Ïxžw7€k˜™ Á�£Z)Ãs„Æ Ô!º½A¨†ah�f©8¢pûäXcy¡ÙúšHùòGª�®�®Þ1óG©W€ ˹&>Ö Ô< ':Jõ¿i¯,-7ß'„¡Z­>T«x7«(ª߳̌jÙ…aÆôÔ8˜Ó K �½@'†‚"BÙórw=A�/88{Jævˆ \ÊÔjÕO×Ê¥W+"ÚÝ g� ÚÛl�ljÔP-¹ÙŽcL¶Ëè=~äÄOˆ„aãp¼rcªQ~”ˆvƆy§gÛWKÖ�˜«,ûmƘ¤r@¡’1�â±^`,5*×<üĩ蹌‘$À˘z½öA"zu»p'©Ó s!BN.�ŽMÌ‘¦ e^a¶¥Ÿå/ºM"Ú àläÐqmíõ´A  ›>›>˜‘4†íëÁì8jL}ãïxFE¤|ù"}�._åÿ�~}ÓÄRh…g©‰Ð÷¡¯8À›D‚0Ì]4Scw¡9�Jºx2g±¯ÇJÌlǦñU+%¯W÷|÷©cð#"e‰�—Žòß àý+)ÿÁʾX/ló…ãid�¾qàè‰{;zB‹”at˜_\>h˜¯5†}›ÌGè!º™é€ýÄ“(‚1«WШUШU1V¯ÂQŠ 3‡Ú¼áº=Ûß/¾<‘€ËÓ�˜°-ûZ6‘¯xÒCÃoßÚ Æ�›Æª¨z.8FDûž8z¢'„ѤV«½ À_eÿFÕ‹vöã2_‚0V«à¦}W¡bïñ>åðð£Üêt‰™Ÿ}øÄéDÂF˜F£þ^¶egˆh@‰_z 2 ´aìØ4Æ®R(•½§&&ªûEù Âhãûþç�üØŠ�Î)õÈÎWD(»¶mžÄæ‰1”(ÿŦ¹ùe¡&¶½?îß³}zJ$|y!}�.#ÆÇDDŸ'"'ê–$ýÃÉàž¨‡hÔ9¬¸BX&ê(ûåÞäx}ß7¿û”/„Ñ'‚×Ý;V-Ý^rÙ!Ýõr®ãÀQ •’‡›¯Ù…‰F-ÊàœïäÄÌž^ˆF3G³ë‹Mÿ³"áËI¼¼ø"€$k—™QòœÄ£/2V)ÃUƒ@<³i ÕJ©9V+ßüé/?¸,¢„K‡N»ýޱª·Àk<ÇI |êî"†Av‹PGŸµ!Q«Ócf~ €Ÿé^>ÈÀeÂX£þ�?€Bê¾ë(x®‚çJ®Jω¦ùÁD©Año°a&ÃLÌ|Û§¿üàa‘® \zŒW«o©—Ë]¥à)‡‘ Ð?(@…WN/ Nn©×k÷ŠdÅ�F "ú0ô{š,µ:Ïýâ·}J$+—&ŽôÜEDÍÕ® Ív§Î.b¾écÑï`Ñï`Éï$ƒ†˜ùc­c1�„Ñ¡V«~Àv (Ü?˜ˆðK:þ ‘¬ \Úœ; à…�B«Á‹«D¾R8 C´»:=^hÐ Bͨ–KÑáíÚ<5þoD²—bÉ]âlÛ2q]/4VDj•﹈ã:ùù`ÀÁÙÓ/É ÂåÁBÓ?>9Ö8æ×ÅK„£¶m™@7pòÌZmMßG7À ,¶:IEÇQ‰ƒ�Ð=µjy¹ÝéÊÀ ‰�I7ÐÀc¶ƒ@²GbáG™³~âÊ€¤™q¿HU.·HÀ©ÿ¢G¶>'B ¡„ÚÎ ˆ ¥Õ²‡’窅À�~{Ó䨳E²—6Rp 3>ÖxU¨ù.E„JÉXÒWöì)Ž‚%×…ë¤Á­ul#ç:'’„ËmÌOÌ7Û¯Pw]‡gç2}@¢G˜â‹; ük�Jö‚�º11ÞPÌøÍxô'�p¦–WÁ¾jf MrçúÝ�Ú¤Í@µ‰ ÝéÿN¤+—GNž êõúM�¾Ï JQ¢ø‡Í ¢þG ÀoÔÿv©ÙúA‘l\ºìð¬þ•Ò–ŸDBƒn í%õpÔ ,s°ýÛØ„2þS.SZ­Ö!�ì`²n¬P#-LâÁ &ÆoÉŠ ¬/ÿeðùãÇŠÄiÀïkµÛ‹Xá²çŸèb@ÒðR«ƒãs‹èô‚Õ Š^ µAhÔ+eTËÞŸnÝ<y›ˆU �a˜oü€—ökw5äàÄ’7™ƒåÏ×òýˆdኈtÇkåWF5œuÚÝš>´ £N€†  ˜Ó-GP2U‰è¶m™’ª²K ɸīÿ>l;Îóõ;`/å°"zµHV®n½fûNÍ7éá3fÏ,%¿ƒP÷­Ì ­3y~d+‰2£†Àm�þ#€ŸéJ@¸Ôjµß#¢U*ÿ•CÿÑ 0bæw/7[2èG® >ó•‡ €÷13ù·;ÚÝ�¡6Åu"Ññqé`6_ÀQ6‰P)b¥è§®Ý½õ"ÝK\Ôëõßcæê:ªOù33*¥üHOÊ|ă scÇ7µ1ü`Ë÷oé •Éäxã­o!Vù²ËŒ£8SÈÉ Æ0¶oË–3³9sàè©i‘¬�ÂÚ)ÿÝ�ž ˜ÍÀsæ(…‚‹ØöÉX­ÂÕ’ËŽR/>pìäD‚peÒ¨×^ðçõl�X#î$Ê „Æ€™±e¼ž[vŒÑÐÆüÙ¡Ù3ÿH¤;úÈÀ¥Ák`Û6“­Õ¥Ü{üê{(¤­€̘ ¹OD+W4_pçØ3«•1^+c¬ZÆx­‚²çôE@mÌë_pÇõ? ¢}$ ðÒàWS_>�`f¨X±ˆ d÷ðÿ#?shv.Ñ Â•K³åwõÚÛ�|�7ª%ªUJhw{0†áDM‚bÏ¿H†€úc�öˆ„% \�õzíE€Ù ˜´j¯0õ׆¾"‚6ñ b(Ôæ‡NÌ}J¤+B³åÿ53‚™©Rö°e²Ž©F cÕ2ª%õJ)—S”Y\ê¡ÖÉm52»Ÿ{ËþŠtGÉ}à>�ÏK÷¬Íf‡û8JõMúËj¿ÏÆbÆUNû¨HW�صuó5cµÊㆠO4ªÄÌ8»ÐJÊý²ë 3à÷z�L¢F˜eÏ�TÊ3³µ¹é‰#'¿/–€pþÊÀMHªöb# :8g dnP»-à¨ìM˵ïüiQþ‚ d9zòÌZùwÆëUžë&!ÿ8Šé¦b:M4^Ÿ¥à(…n/¤^ ]cø“"]1�„§ý"š $RCèkó;¤ÛïXµ„Éz%1¢ãoÚíöÉ ‚PäþGž|/3¾Ï�[‡?ÝSìO:¶Ī¥*ž—Éw8û}A �á¼k4n$Ð`D7Xzsq^Égžž£Pö\”=—ˆè×D²‚ w:ð~�dŒaÃÚ–õ°¥ÄñQñJÉ:£”ŠŽÊ^íÛ¹u¯HvDÏ·ˆ`ôh4êc: `2 Þ“aΟ­¸Tc;ÃDTªcv�DøÖ¡swˆtAX‰gß´ï+®C÷ÌÎ-A) núsË5»£–À cß?<‹¸,9^‰´ dzG(ÎZþ€;Ξ EºVöü§�<ÎàÉÈ‹§ävAE?D ¬ (J$ ׬ëü•ˆðy‘® çŽÐ눔¯ ³6HöþEpÛú—¢E%éÈý%ÊÆ2¶aÐm‹­¶Œ –€° ào Ì Dq?››ÚÚÅ®�6×ߌñjeÏ&òX+;ÎÎ ‚p.vÍlþ¿ï¼qß?ÑÆ$ËŒ­°¿µa<vp62�l•@¨ L¶b -À™¥X©z«Ù”¹#†(ÿ�xÑpÃlp³®lƒŽ\Ïî´q÷ ̉„AX GOy—6f>]‹’^" "¡FÔÿ;E02 zAˆV§‡åNËí.ší.Gùÿ\$+€0€z­¾™£,>EÇQ0ÑÀ`�™$Üo  @(y H ã?H×?AÎ~m’bÌ�³sìåG¦M�ˆÀD`6ÐÆ „è!Ú†h2 &cÞ[¯Õ<‘ëè ­€G„mÓã?aL¼‘Æ(¹.´18>·óÿi…]¢´"àÌb‹]GÑÔXí_>1÷{"aAÎË;Tæ>fú&3Ý‘­õÏÿ‰¼ÿøù€~ÁQñ20àK�îéJ@Èà¹Î¯—K.•K.Ê%¤¨ÐÇŸ"åŸö�HËþÒç°@ÚðOš{¿HW„óåS_|úáXå+EPdì1mlT OùÇ­J2KwÕ«µ×ŠtGInØ¿ë…�ÿ-Ò²�@„˜=½˜+³IÛnÚrà ŒîÃåVKί Ä+ïyæ¿PDÿö»OƒR*‰26Ûh-â¾Vä D¨¹ l’õë`Ë÷¯ÉJ@��˜×E7­Î^£4.0pü/ˆž¹ ‚°~âÿGJõº¡F/Ô£#ŽP›C’IˆrÈZ„½õzíE®ä�ŒÏ;›qµ”I\‚ \0ß;xì 1Üsy�“ßí Uú½P#Ðf5 دÔëµ·Z~S$”̦�� �IDAT,€+©üS^ñÃ\Øk+~š Àÿ± ‚p¡<uìT—Áß*f ¯4tð”;6¸K¤+€�U #*ë³ }¸ÿþaŽçmG7`jRç²aþ¦ÈU„µQê#ŠUb0óp¥/c+à_ˆd7ÙzÝ€òwÁhƒPëÂ'ÓÖ›D@½âe¦sQö>ûŸÇOÕ"YAÖ‚ Ô\.¹œ¨µ¨6&Y´1´1|>©å/©×k{Z-ÿHX"�W,F›žÑLF3ì¡Qlô›Fòÿ²ÑLY ŒüaÍ86w&TDæûÚ4;=´{!´1`ƒ¡#Ê“(@þ½ßéŠpŲoÇÌ>fÞ‘Þ±âÏŽúM•~ró!î @Å­¹îì©ùûE²‚ ¬%|E±R¿Âïèq{`€l%3¡hIvY‹»Ëùòz½ÖéŠpEÒ ‚_%¢JÖÝgºA”MËù(�à:v*W 5zaˆ^ÚÞÜ¡æN/üŠHU„µæøüÒWgç—i©Õ³LvX™=õûÉÎ*`��ñ¾å €W‰tÅ�¸â¸~÷öwyŽóÎAYý‹~Ëí.%ÚVJ.Êž¹Újá—E²‚ ¬5ŽR_TŠ@DC3�•²9®ã€ÏQÍ”AJ–Å�¸²Ø¶eê^~�÷—ÓpÔ<ûРþ†HW„µfi¹ù$€£‰ïN”tŒG—÷uÌô.‹·2 yL  T¯×Þ-àŠ`b¼qsê/pЧç)âË\èö—‰ Å}ÿ3ó�˜6ˆ„A¸ðAD €®£úG©|‰`1ì?ðO‚ü|½^}´þçSXo®Ù³ýÑæªÅf»ïp¤Ü;½0jLO¿ßt.pØ÷Û{D‚ \ Æõ*-ë—¬¬>B­sÑ€þê¥ü †ùõvçS"åõCú�¬3·\·çÍìµÁÉùåþ$Ùþ6™¦x‹Å7ç,8FÌù¯"aA.å’×ð�3ßÙ B:ïn€™7*%ŽÊ}ÿ#b�¬/rYgzað¾n §lÂLîpÒÖ՜Wæ#"aA.sgÀ}Xmô8S˜Ì¢ô-‚a`²Qã‰zmËÔÄØˆ”Å�¸,¹aÿÎÝl³hÏo÷…ÏýÞ€Y‘² ™?]Ų”’Ɉs–RãÀ>÷\‡<×a"z‹ˆwý-€u…Ÿ›¹%†*wzõwŒ^a?LX}Ý ÂÓŒ|mËÔD8HôUd8Æ–ñZ²HUJ%(ÏHÖ¾ ¸,Åý+r¿Ý³š;Ré*:úÕ»¬A0ÑÓ9Ñw8šðg­–/€ ß•aüî@'%j¬ã¡e*=ˆì¸`G)(¢¤g@<[€™©^-ošÞ4yƒHX €Ë‘{°"ÂüRk•›�”ÖÍf h •¶Úoù âa=ÐÆ¬˜p<(9ˆÐìôVüN´¼½C$¼>ÈÀúAóK­WP”7{®ìÙ©ñ‚PƒÙ>f@`ààñ³€ÊMÿûq¯ ëh�œ¨ÉŒFÓ§Wˆ›7@F‹p9Q«Õÿår«ãœû`¸Žƒ‰FÝ@ƒHÁÄ÷”黽ÀI>-a½`Àx@¶\iEï?‹B´É æxC3)hffž ¯²°ÔëõDx/qÜÕO™aŒ¡­£#ÔÛg&„z@ ¡ï6$�Ÿl¶üe‘² ëE³Ùj3øŸOÇÿA¢Û Ðíèõô‚^@~/ôÜry‹HY €Ë"úE"ª$“{£ZX[›¿…€1Æ6œL›D ˜ ÌøC‘° ë¾®¾^ìT«°8%ˆ¢Àh´:8Š1^õª›•OŠ„Å�¸äi4j{�þÛÕ/ýAîqÑè¨Í`Ž¢¸E0;Š =.RaøÛt…Š{¡Ö?ã¶„ZCke×­ÜVAö3³aÜ;³iâGEÄÛˆ.*õzí>"zƒ¡ öV|“d#�Æ0öîØÜVc�1ž:zŽc EX\nÊ9acÖ·F)Ó²œA0&°+™6÷Þº¡ÖxèÀ±¤ô/§Œâ6çÌ0 &¢£�®9uf¡'’–À¥¨ü¯!¢çbô¤(»ÉÌÇEÊ‚ l VùgØD¹M6¿ÉÃ6¿)Ô&3Ý4 `'�nv‘*€‹ ãÿÁ‰•wÞ Áé3,µ:™ÎXégün['‰íæ9ê±¥fKä,ÂFñŸüHüDkƒ{nÞcòÙý€Ý8/Çï„”ŠpÉyÿÕšð eú÷¤ã¯Gî–Û‰A™¼�Í ®I^�óc"iA6ÌÇÑæ!&,h� ÃÖËOs�Lâø] syOѧQ €‹‡l\4矰í-㤘4tŽïæ>0«Üw2Å�aÃðÛíãzŠ(iq¶‚3O}ëÜ@×?Ù È™Ù<q·HZ"�—%×½«h^Å—u¨ ´Ñ�¨¿Ô×Q}ß½(„æ¹®µ¦% ÂFCø{�·®ìÍç½ÿ¸Pk»Uƒn QrxŽŠ�ŠÖÄ×�øšZ"�—ÒMq[ñ°Ã|lÎ,Q|‘SßÍ’µ—óµÿÙD6 œA ‚°±°Êö/†ÌW9p•“ ?#²IͤT¡$°/ŠðÜé© ©v’À¥Á–M3o3^û½ùó±#âÈ�Ãs®£¢š�hŠ´A?rðps¥ßzü0¥Ðîéª~Xavð�H9 �£O¥äzl_ò»kP ‚É5× ž�‚ Œƒ†Å££6hÔçâ¬ô'g"]%€�—�Ì.mëÃD—<ƒa†øú”ËÈß ^hÃfàÉ �A6š^VÑŸ]já詳v¼of³ëÚ gç0�ãq9µ À¥`�\ d/Ø´ô™¡:1‹m!óŒ3ßWXò; G±b°D�AØøïk�ÞÅÌPœ˜_„ë:µng›Øáñšf2Kfqd€s‘Éàè%ƒÌØA–/6¹Ïæ»Bó:²c ‹ ‹M#ÂaƒùkfF£Rb�d™QaÕ#,û=åÊü’w=W¡ Ìp”Íuju;EÌkT\”��¿4ó8wÄÚÛ&Î*+(²'Brý°Ó>�qï�` `ÀPˆ¤AØhZ-ÿ¤]²˜À™Ô>.úEù,¬‘ñkö{vŒº €K‚P›u­³ÓýRg½\r‘M~É^ÛAhh1¢åØ �€€‡DÒ‚ Œßð¬¼Æ_½ßÏ ˆqT å/€K†©‰Æìþ?§ƒ.0dè÷ý挹¬ ŸO¦ÚÈÀÃ"mAF„/ä˃ÖÇÌsb $"`äÙ»}óswLO¢Rò˜­i£ «Äi€‘ÌýŸ&²²áhºÃ#€ #O\äâ—DÊb�Œ<žã¼¹Ó íHÌÜÁ@a÷üeà¨tb3£Z.¡V.ÁóÛÓuá¹.Jž m8 ‘–šÍGEÚ‚ ŒˆpQÓ8œŸ;â逌•›p—¢ýÊøXC¢�kŒä�¬µE¥ÔëXàd6Fâã§�í#ŠuØ2ÙHn¶¦Bò‘…fÆxŽ�¡HZ„2�NÇ;==P»ríOèÜ@æ!ð³�~_„-€‘äÙ7]ýŽ^œTŠl¢?ì®þ`cw)œï‡½‚, €A%æm8u¤ìU_þÓjl,8éAŠÀŠè"f1�FYœ@Ñ0Ÿ(ØŸüD#|RÉ–�ÙщâO†²$²adV>¢¹ 0Ü t¡Î¿ô\l0dK@)‚£ŽCpG)RŠž¹irü6‘öÚ![�kæýï¿À4�6lÂF¯aÿÃŒ^¨±Êº™"qAFÂ\ªÆyx›Ól$ P÷ŸËˆfθ§¹éÇ�Ü,—À¨q‡½BsWxßÁ°­€ãl~m¡ahm_çÕÕÍ~SÄ-¨ÐòýáJEûŒBc4�eÏEɵ‡ë8É‘ŽJÏ`�7nš¦H\"�#Åübó¡Ó ²æî ßàœá%О“Ð&à["qAFŒG"Gh eÏE­TJW?fÔ+¥$0pr¡9ÿCƒ±%ðv\`ßA"�kJ¨Ía¨ã¾Õ…ëµÏ’íûC Õ²‡Z¥Äµ²¥èÛ"qAF ƃ+í`:JÁs¸ŽBÍ®géˆs.(¥º2ð¶D�F.äË`©éŒ0{¶m†RD�¼ÿ‘'q ‚0bÀ·“Ålµë^¶ó_aÝÃðLgóäø¿:³°ô"t‰�ŒÊÅ¿/šþ—éˆ|f€ç:ñ´ŒÜADQfÇ/½M„-ÂÈAøÎš/«Ì¨”\TJnœ0Höe~·W.×Dèb�l8{·OïJËø²‚þ JúPt¤F@Ñ0`�ßÿ‡Ÿü®H\„ä0À½¹0¿ «U0V«¤§<G=GD~aÈÀÚ˜¾ÏfÙ?”){)L�àÜøËaÿìý ‚0’´|©^¯ÚQç¹%Ì$k¡ªèë•Rî…¸j luTš¸Æ*¢ò;�îÉ‹°Ñ</ëú3†ép"BÉur>`Çý–K.B&ˆtDÔ‚ Œ0¼b³lß‚K_-y}keÑŸ"¢È8`Æ ‚�ëFw(ÞœB¦?㎉ã&·eÀ™%z¼]¤-Âó}�×z£\r19Vð7YÛB£A ,5Û‰Qà8N´A:Ì“­)Ä�X? ófÈ–µœ«À�#€câ#ŸP-—†ë—Š´Aaÿÿ; \×_ÈÏp¡\òÀ%=ƒÁLp4Aa�ÙÅŒlŠZÒ(öÌ…fb�¬Û7OL‚¹„쨿xÐyØ�ñØLŽºf#�~7ÄüR�&õúíÍVKrAE௕›¦5fŽõ¶]ɪe/·Þ!·Ê¥Š>[þÛEg_)…‰j ¾ï‹Ì/�©¸` ªI(U†R�˜¤ @œ¹'†íël Ød4!˜Å�˜ØþÌÁd­c¼E„.Â(Òj·?ण¹Ž‚ë(8ÁuTœÁWÐæÙçñ@¨M¤ü“ògÛHã–éF$°¡L¨¬ZàŽ]ÔÃÃ4 ‡@æ•ç‹ÈAUÕò­�0“u‚rn=Ip¢1ÂéG 'ç—ADØ:9êxä°ÈZ"�Ï�NœÐºªk’hp…l!+–“ŸÜgo‘ ‚0ª”<uÚÀ,÷„‚Ǫ¥’u.ÚÊOвüUtPä Å%ÒŽRI €£DûK``6·ÇÖ¨1€‰’ùâ¾ØšUP`0¨OÉg=@m0TÆ>K7VmAXoô.�×ä<ÿ!NN¼î)"œZl%s^j¤ì—üÕ2<׳Tˆ°áÔk•geçY”À ±Üî%¡|Êì}õBƒá&�ÎqQË/ÂÈó\½ˆ@Šúÿ“üV£Ø‰ú×NA €u§äy·Ç–­àÁQ„åv1zy…Î}>ziPÆ AUölŸ~mV¯vϾ鷱Üj§Ë „rÉ¡Rra C땼{­©Jr�Ä� öÆ&©›©O�¦•œ7Æ ŒÊùÿ6̯5£ê|Flt—Tʦ§ÉëKË-‘º £È R=5R=Ÿ,ïûÀd½Šùæ¹Êú¬õ@,·¥1ª�à��)B„ BÔî7íég :öî³_¶·‡1&w‰ ‚ Œ: ~30·Ð´+%N;ªG&¶âª(Ï\Ö×AµëbÚK@`ãø&�™J%‚z.ƒó‰|ÑC¥n€J¦!øÜ{þ%ÏÅXµŒn/Ä™¥4B`Xr�Ä�Øx2¿Õÿ'vµÈY„f¬ÑØsj±éV©;Jå–±N7Äd½ºâZh¢¹'Y¯Ÿ�¸J¡K¢ôÅ�=þÀ/¤újÂöƒaPá}`‚ Œ,ÏQdGžÇ¿3Óû†~‰™Ñ B,·»Ø>5Ž^ sï÷BS‹M‘®�£G¯¶¬Å (RhvzPDùÙÖÚ˜Þÿʱaf ÂèÀÌû6 Ñ¢'þÍLŽ¡P˜ ˆ0ßô¡H咃СÖtj8Jõõ Ä�Ø<Ç©€Ö½ @³Ó…Cdg[sƇ§´ÉOúꀎ�Œý}¹ìAE pµC…F> qÿB®µiÖß¾i"2"ⵯn�EQA €Q²{ߟUæñåºèwVˆ� è†E„JiÈp Ø;»,¢ad!`÷@…¸/”D rP�%ÙýÒéO €‘憽;Ê�~€™™â>@Œ^ñ×9gáÆ­ç(¸…éVÌ fk8t»ZnAF×¶ÅëVÉslHý¥Ï}þÉGcQþb�\2¼)¾XÏ,7mˆ�óê/^GÊž;ÐV`ünÙÅ$ �‚ Œp€ëñB¶móÆj•H™sg—¢¡>@šá&„̧àâN{ჴ¶]þPèó7ð2Ïõ¾¦s¶ù%¢4dÓX„‘c¼VžŽ§ù%%€ÈÏÿ‰‡¦¥ë?í–¾’ ÀFs]VÕ'#iøEÍ«.vÕU«µ™vÛ?%âaT¸jëTC‘uhBÍ£Ì}h“¬®r.øßbæ´Ú@xÚH¼å  A�SRîù艒v\è?‹"}AF…gßtµÃÑÞ'sÞíOû³Ùÿ}KÚÓpŒ$� €ää²€ÀD½œ4°`føÝ 7ƒ¢ë{X-?ƒAâû™ŽAd£gWø¶œAFB‘8î`–MìùƒÚÄæÁUP«ö€¹-A € ! ÍÙø±Ñ&¹(™ÙöˆOO'@Q±cpz±‰@›þ·#‹™‰sSƒ\-Òa„Oüœ!Êœ�œ\jÁS*çqÔ@öôÅ�¸¤ ¢ùĪ-X¨žkÃýÚl«Y¿pc8ŠðÀ÷Ž ä9‹3°9o;ŽÊ¾w‹H_„bgªýŒáLo‚6iŸ¢üÔ“ c4 ¯>!0n7,ˆ°‘œY¥� KÞ_± Ó-+×TP �AF ÞG�ÀR³n/Lœ˜3Ë~:`ÀòÊC[]$@z\8²‘²�Dv0vöàኟ¢³£¢9ñSX¥Õ‚ M«Ý»;5Aˆ a¢1¿±’¦ŒÂ6`h˜ä8—º÷üãòBG)%`ÿ®é‘¾D�6г«ÿ耀aIç LŠèAÀï¾aCÿqkß•<ôì&�í—b#J)TËyUUöl)a'Ð3�¤$Z €õ‡™ÏæøðJÊ›Wó÷’ñ™XÁ6TAF…ɱ±Ö{<×eE (•nNv«3é“2dEdf¸ž%SÛ¦A¶Þß¶VOéDÛ eב€�ÃôDãLlé6ÛmZÁûç怲!2Í€R˜Í@-_,ŸUÀQ‘¾ £€6æ:Ý%×)Âÿ�à2ÿDSó”¢ê©Ø ˆçønÎ/Š'2 €�8Ã�ˆí°K2ý^ÜÈDÞýR³¼ë(…’«à8Žý,òí3K®›K̼ùÝE(Â@Doõ­RC“þúRÀó\˜§W¸E΀�‚a>›xè™þþEýØÉùìÍ’ÜJ)x®B)ÚÏb6IF¬1„Z¥œÌÇæÜÄ,ü¥H_„f¼Þ¸ Œ©‚A¬o«t¥ày.´1çì0à]‰�ˆ°aœÉöÍÞ…b€Ý Ã0#mç,×MoRÈÕÄ’"ÃllLìë"zA6ÞýG€S\ÿ­¤#àð¼%f†£š~Z¹ï=ªüün(À e€ÀÁÙ9¶"l�Њ÷Mú à “ìÿSNóS®>Ä@ðÔñS_é ‚0ÀÀ….^Ó èÌ^Ü 8ëé+"aMŒœãDƒ'ªhmd @"�WÀ}Fm4�8{·O×ÎÎù"AFm :½^NÑjrFD(—\0A˜sïû€v7ìË �ŠÔ¢H_"�3Ÿ5ÆDžzòâ O¦Íý£v~ƒÿ`!”­àäœÝ#’a£±uÿv+ÓíãÇ~¼f=mb〢¶ÀÑãŠ?v÷ã';iÕØÝ×r$°aTëå‡Ï-<_k“\èj)× §ÕsÙüj¸â/¾–î(fþÜ5»¶]ÿÄÑß—3 ÂF±{Û¦2Àn£o·»èö‚ÄÛ¯”¬Š)Çå} ´ºAT&˜­v~§‡z¥”¤çGm«ˆpz©•«.ÐÆˆ €ƒ߯€}­üg¬•›ü޲›YñžWôÅû`*M ˆ†hp  š½à›×^½c›œA6L(ºC)å)ïÛgœ£²—¬é¾þð¿U\C9z @òýøïEK&�—³ € Ãsœï8ÊIXÚø «ÙÑî6û.èb8€�´ÚAæâgœÝæ/ynd � ÃŒ«wnnà È` A6f~[¾Ê)Óâ·ÐÌl°wô´þÍìÓ“r$°q$z4ÎtåL¯Ë¸e£0 ƒ2Iÿ0½ HA‘J û‘¹yz¾ÉgZ7ßxÍ®÷ÊYa#ÐÆ¼,›¹_-{vx£ÐjwÑêô’Ž~q®€mfP.¹Éç³éýùu1;"ûª65j`ãBÝÞ½m“ÞÕ4@uP…Åâ•Ôô-Týõ'¡„è!ˆÆX¢ÕîѲßa0Þ}ý¾59‚ ¬'×íÛñŠâk®c›šØÙ4é©ql™šÀÌÔ8f¦Æ1=55M£\t Qêœ<ÀãÏqíÎiɸ�d à!"°L&«¿xgI/æóˆ}QqzVÎ^ØÍàí�ÈÙaù±ì“P›(±Ïfë3ús£¸¸/@@¨uRØ 5œ¤ƒ`´êa¡Õ3cª^Í.¾ø»oOÊ¡%°±0¥Ý�¥ T|ÑçSû)šg³~9»W–~'ûW2§q•Ä êurAX/nØ·Ë#гâNƒÛ¯Ûƒ;o¸›'Ç1³ybh¿a†6š ŒfÀ�ÄbJ:»¶Ù µF 5<ÏI‡°gÛtYΆD�60`{Çï¦FmnFpÑÓçØx-´ àÜ,¬‹Ïœþ 58pð�¿+'C„õ õ)ìTD¤£úmŒÍeb3%3Š„¡ý|ìqf™$Ø\‚¥v½PœY[ïð9#b�líV'RÌ+S¢Ñ•}³& ­®ÄŒÒOÛ&ò‹åL‚°^Ü~íîëIѸ"‚çZ5¢ ã}ãuNk“æDqÿ”@Em ˆË.–ÚÝ$ppæ”"D¯@ € �¬Xךªñ-ãõè³ÜWØîý–2§ ~¹ÝÇ—~¡‡öSÇO@©Z­NµÛíy9#‚ \lx'C?2ƒ|è…an}3†“š~ÀV hc’ÐÿÀPh¤üç–Z0ÌØ:ш—»äl<}$àѤ ì~38²d¥¢ƒ P*~Íö Vö€JöòÓ}0[ÈIU=QЬ X)P”O@DPJI{`AÖ…8päÇ[ín__<óš=¸ýº½ˆ»£šlòR6‰I¬ìÖ§ëºp\×–@Û%JÙýÿø³¤hPÇÔ­WoŸ‘*(1�6ÃìfÒÆ&þæÕ}qظÀÌëÃÞòÞÛål‚p±¹a߮ۑK6Æ × Ðë0‘Â×:í‹Â™fÈúÈ 8Šà¨•wü³ëc<&8Ô¦qôìbIÎÊÓC¶�.œ�€!@æ¡Å}qÌ8366ŠAiÞÔÀ&þ!©’‰B]éßöÜ>» xYKÎ… Ÿ÷Äê8ÞËOBüÑ/¥gÏÂs¼îVÔ7%ˆ’hõIuºFR¿± ˆpvÙÇôXƒEgBm¤P"�F€Ž÷¥jåRæbåä?¹°ŒÙ³K6Œ)»fØ Z*¡^.ƒ‰`¢{(Ž|3Æ%"°"L¡TÆ"0crjbü­r:A¸ˆÞÀ›ûs"tÃ0°G/@¶C Š·*ãlf Ú>µñd›¤1ƤGlÃ<»Ð¤S‹þW9 zrf$°!fŒ�@YgÆ]È„´¬ÕšØ¸ÑÞ}êäŠæÃãW¸085ˆ(o]Û/þ€ËYáâÀ¨’së£õíñCiS>• ég—¯({?·ÍIX)ìOýùψæ¤}ßoû?)çD € cÇôÄ23'S|Nž]FwѼrAS) ­Üò2¹ˆ†m30€É©‰ñ{æ—î“3#šzÿûw쇡·6l S«ÓMJÿ²3NÀ™úþ>w†lÂt¦IP<)uµÀÄLOñ½rVÄ�ØØ€á&€^ª£9—¨ZpÞAQ‹k6Œ¹ÅV®ÑÅôøàdV¥:Ý–ÝÈlŒLŒ¸SÀ@„µõý÷€0І³§rûù®ãä9 ñ侹¿Zð‹ ¯Á=­VÀrV. ɸ@îäÉ€™ÛÙž×iBL~z•0;¿ŒÛËd�� �IDATóË8¹ØLªìþŒôEÎyBš ‚°¦liŒ9:0?F5ýJÙlÿ04è/i²J»V­ ^-#СֵAj°a¨Ì�˜è'·˜E ƒ”RÉÁ¬Ž�ô"ßå/€Ás‡�ì�Çqà9 Ì ×s1lo‹™¶g�Ø*ZÐA³‰mجÿ-ðB9#‚ ¬%±Ê{Â@«ìR£µ-õs3¹HYçgj¼¥óË~)ˆÇš÷/\”¬mçðqîjµüŽœ‰�Œ_JŠù G7Æ*¿É¶†– ZË7¿¯f¢™Ú¶õ¯}-Ô&„öhÔk¯”S"ÂZÁÌw'Sþâfœ–4yùöÐZãôüNŸ]‚"ZýzXôPÏMŽ%ß÷ËÙ`Ôn/Ľúvl™Àm×îÂx£Rõ—+iál‹?²ÊÿDT*¨¢ºØØ�à¨ÄpûÔ˜M°‰~Lf Á˜è°7é{䜂°fŠB9u¥(ÅQ—¾Ô±N9©nŠüû:D}>žs:œ\A_�H«s1�F¯ýâWнõTï÷ñ‡ÏHúcSÿMQœ°rLÏ«793‚ ¬•ß&,5},,µ0¿ØÄÙ…å\¿;Ü7Uÿ<8Ê8=Ž£à¹ù-QöLŽÝ"§B €‘ãÀÑS>qìæ›çהг˜¨Uú*€Õ¶æø¿Uól9+‚ ¬%«¤SmoS‚€0Ô6Á/£ÄûMûÃÜ1µ¯«à`~[NÅÚ!I€k„£è~�7(Ê\Èq Ë 1¿ñëQO`w¸ƒÙÀpšG`¢F¶™Pv[!ŸyMИ"õK�¾,gF„ áê[Ë�nŒŸ7;]tƒ¸]/¡ÖsÓ®§ýZ¸çC«ñŒúxñäøØôÂÒòœœ1�F‰�¼ýÌb §šPD¨xV¼žëä®ç’çÂu”µ†™¡CµêÕ2êU/¹;ÂÌ,m»çÆ™'_s{r±™XÚÆ˜×ÖkµÝ-ß?,§F„§ ³¹[Õ€£90vè¯R±Î¬ÕÓ‰ÁŒrÉEÉó’O·:ÝÕ' Ú è)�b�ˆ0R<€E©üÉÍÓŸôÂIŽ@:AP1õ½ 0=Ë~–r­3iÁÌÑÿÄð95‚ <]N/û¿ÀÁ ïžÏåêGïfÚùÖ«eLÔ«É{ín�ÍçÑhAΊ�#…6æ)Øñ}7J„¹›@E;;õO)|“ÌÀÀ;®88_e¹ßÀskÕêŒßnŸ’3$ÂùÒ¨Uo‹œ´Ïè³/õB»Ié¹ù*€øQ½â¡x®ÏuQòòKäD£ ÃŒ…åBþì  —›²ž­’¸FÑ"2qL6&}L‰zN>)sÊæÄ¥”™÷b µˆ™J©Ÿ³#ÂÓÓô‘¨v™rãø’uËvùë…:7å’ ~ÁsTK%Œ×ªð77°^+c¢X´D�£\òP)gŽ’÷÷rRÄ�9Nœ^Ð�¾°†D¡|¦`gZ‰ûdÿ–1æCõ­5’3$ÂyyÿÚU�nˆ±â°Êû%Ù9åQ“3Š·5©ð-ÎW×¶¸ Š™1Q¯ Q-ÿO93b�Œ*ÿiÈ­‘Õð�€V§“LÒJÚ2°ÜêàÄ©Et»A¿‚7ŒmÓã¨V<wý™Û¢fAÌy#�Mü†œAΓ÷Öÿ­Ê0qÜŸWÐ4Q#3u Œyʉºþ9Q‚t²°%ýÔÊ®‹rÙûS9-k‡ä�¬![ÆÆþ|¾ÕB¨uV3#Éé#kØJìk '› ÇÎÓVmdª�l9`<>89àÁ Æ[ëõÚ[-?³$Â*¼ÿi�?/ C-�N=ýv7D£êe]÷~o(0ÅÍÓs7†±kf2Iž.gªzAxú»O•ý1�F“‡Ÿ:ÂûvÌ<TvÝ[�«Ä+Õr=Ëöñ€…¥etzº¯R€@B G)[ëôtmòóòFFá¶#\àv�ß³$Â9½yƒ_WE*UরȨt™IfÄëA®2å+\rlð“ÓŠ¨’ë$£Ï=׉kš¸„Ê™`¤aà~n@6t•îË;ŽS0‘$ÿ1 kM³Í Ep9”Üj†õÉ.èÎXèØpÞkä ‚°õz­ à‡|P1Y° KLñ­ûû0cËøÕ2�Öç˜(ÖŸ]Ç(‰±íµ"¬!’°ÖUô¥ˆ”"8Áu®£à: ÆhhF‡†É ìä+W)(P pâìŠóe3JÝà‚•=HY«ÝàÕõZMη çrcîxoêËÑø^I~û“ +C:…È6RDÿ?{ogIVÕ‰ψ·F.•µwUotÓM#Р€*‹¢Ž,Ž£Œ ãŒâ2®#úAuæç¸: ãnƒ3.¸Ã‚"‚ÒÒ «lM7ÝMwWuUfm™•™oˆ{~Ü÷ÆòòeUVv-÷ôçuå{/Þ‹xqî=ûù!ÔßIÈŠ„aE&Dð?9Þ¸Àå}C}ïÓ=@Dä ‘ácOâ8[̉”OòÅíà{~f%{žÏQ\iSëšÁ™¡3Xí®¯ðvÇ%GŽMqþÔTè2“4¤=ÓͰ§÷m' "t[<O`a¾kYå&U %pë‘‚ðÙGOY©ÒT&ÎuÚÿèxã"�—5Ý÷ðÉÏAÁT’¹1&qRi)oEž'àyÂÚ,Óˆj,tôUŽCŽ9ª£n·û<�‡`aüQ¡»Ï|¥Z•Ú•yºÔÊRšF” })J$R~æCŸ~ ç8ä €+~"ó»õFH¤,åíÓùÙéFÉ«bõèLV€<! v‰ @ˆL4 m¤£Dã¨7 2³Ù‰èÙŽ5Ž9šBß…Úà"ƒ!Œ±¾•C}ADØ¿4Å…0/ ¼À‹ÑX&H¤ümÇš's èö›® ¬€¹›zñœêÓ¤+d£8Áúf'à>�†€ÈŒ‚f@ñ$ÒEŽ8O²â@.ìÚqgÂR2„Ȭì ×ëÇŽK…ÍÐG f`®Ó4Gë›}y%ýާÜvãM�nbæ›ç;í—æÃá‰3«ËËgÖ–AXfÆ "¬ ÂÜæ0^J ç ´À€=�/�X”Rî¹éÈÞù†ì0Ÿ$Ò‘`À©Ñ8úÔʹõßÛìõϺÕs)½ÿâH{f+~A)›ƦÔQ-�BŽÜSú\*©ö/Ìa¾ÓVŽ Ë:BàÁ“§ ΃€ƒŸzà¸kÜar5�—€˜yà ñ=›HMÿ A’a€eL¢ãñ$ÁPVY^ù'$Q!…À�|ß+uÙĉ4�†r+Ú¸¶ïðkŽK—PÁw;m�Oè¥�žàF�בŸóBX%Vž'°´8iGŠúú‘$ ç㥧P3ð"ƒ˜.ZújµJmS" 4²®æüS¾ïÁ÷=¾GBˆC%°)By*ºYŠIç ˆ²:¤<ŽL…‚Šef±düÒü\ø·|ïúfï·Ê.M^Â,fUl½&E†R. Œ�UÍO¹+–JKFfΉ¹Žˆ€ûŸV†>”Ç™yÝñÇ�W}ö‘eù´'Üüç�?ÄXœqôàþÊc£1¤eh@¯ýÑ$ÆÇÏ€ˆ0¬@¼éð:­†%dW×ûXï P"¨?Cú¹0ì¾¶×ë'ŽS;Onø… ~‹$ <‘74)#Ï·Ü*–ªÑ*:OLåÜeæ®âpýÁ}˜Ä1Ö6z…‰ÈæFäm¥†`-¹peíœE’|¥ø)+ØRßE‰jQ„†J]ezž8¿ÙÃò¹5ÄqqY忀�éžï*«¹Œ™É,1OÔwª~53ra.<²¾ÙÛt«m'½ÿ΀ïÛÚ»¹ø°1°v­õÅ †“HwäiOm€Ü`2vlrÀD¿¦ß�XZ�B�ýá ÊŠ/ˆÌv'ˆâ¯Z¡=µ´ ÕôA�ã(‹ ¤é /æØ·ÐÅþŬ¬b³?Îd+)€êø�àX´ÃÊ¿Ó9$ï(TèhSú4´\¬vNžŒÖ§ì_ßHXµO¢:Êc"REñ¬TåÛÆ�!72üv¢B êÌ$̘詗©÷–¸"ÐʃҪ” Ä*"ÄQ¡§ÀŠÈHÝS ™ù¥�~Ç­¸¥—AÁþbëŒ}]©ñÖÖaem£ÉÄúÔ$J0œ(ãw®ÓB8N×-ø»~ÀŽEÎ�¸bèc÷>”<í 7ÿ€—,§/‡.¾žŠb¢’`4·é"ÁT$œýYJ6}å÷ð»Öëõßâ8µ£t'hÎäeÚ:“xdÆW=ãI˜ÄŸ:Sòä唸¿'@„X&e8öíô‹êóœÝè—>4ßmb1èd×Zú]¤ÖfõÐ0²Ú«cp•§oÑd¾Ö•­D%CÌx¦3�vŽæºa'Aò+dÁïÐŒŠ½Ð® •Þ"pM*2-l6¿]™ AÛ3ßA06gÿ¹ã’3�®8š$ñGÁxY”$ˆ" g!`Ò^Pä žgµÁ¤ùþ8–ùÒYÃlSÌpE†Ýçõzýw;N]<u»Ý§¼`ÄÍs>p^4%¥•µê5ReI¤r£DPèÆ—¥ŠÞ]Â[-…ü‹éí[ciå°öÖ«V鎻§[J†ŒÕ5 òߣÿk>Àª8Õ>«ú-k›°d4<ffʲ˂íF€(–˜Ä1�´ÜŠÛ »]ÁwW›Š´-I“r]J‰‡OœÉŒ=†šäG”¬m pxïZÍ l,á¦#{E1<³¾Üï9N9àŠ#b)øE"Ú×_­}Bÿ€¥‘¯ÔsJ‚ª Êe§”Œ$‘Yø·`n«pkyܦùô®n·³¯ßœsܺH^ö2O“šJ YœË¢3‰”xúí7#Ir%?á ÛÂ8ŠñÀòŠ‘�‚ÀÇ¡½‹’±¶±Q Í™RM¯$C`«aÿˆþhd¥Lïm½7Äzoˆ[®?P2š�ÍF€áh‚ÑdRøåŒÀºÐ/.+"lôG`)±!4¢ ©w(Ð |0GE "rE€;GßàN­ýíP£ à?ÕŸÈÓUiSºîâ8Q&`!m%j¾–Á B]E2˱È�W¨VPÿœßìミº_ú´;”Çg(åv«‰Ûo¹ç7zX>uÖêh6|<áÆØèñÈò*¬¹Û <¼²Š†ïáÖ£ûsa#½þÀ"ˆ÷?“ Ý|‡µsïît:O ®(ð9̉Ȟ ™Î‰°æ<ÔzæeA9íœDÕ CUi(@ƒImn>W¹RÜxË-£¦i§Zùô“neíˆ÷€?*‚…?¦¶žØ|zÑ?‘ž†ºÙá®Ük¤ò§ Á&@DRJùÇ)g�\™Âßï€ñd’‡| v2‰”'(Q°RJ]h _¡Ùð!Y‚ãÔ["°iÑ_A¸WnóÛ�¼À·;Ž] ñ¿�#-¤ÒuûºYQ§/ü,CÙõÇckD‰A P…9½à*÷îuÛ-´Û lô†YQÞ–W^ªAáJÇoƒÂó<Qè ×%ªÅÂÅJ5@”I¥µ+X=¤Ã„¿xå0ø­J#ïU–`*€ìç”óp¾Û¶€ÌâDf­}r‹žÕ8–YÙaI>1³ :5Ž“Ž[Î�¸"i<Šî3…ìÇN‚ÏÎ Ç6û£J_,Í©â«(–¥¸z¾Ÿ ̰ÛD[OÚšUsxY§ÓùëÁ`ð—ŽkF½Þà\·þ*À¯4\•ËÖY—„%ù¯¥ž|PZà™·á¥•þi}“ÂO·²ÿz¢šªf _±•®€ÞF£7³4Jl.´"‚0ŒíZ}hxh4¶%"ž°‚Ì’Aàa<‰AºÖ`}ï OµâuçÎ÷»w‘æ*øè6+À²Í:û(NðeO¿Qœšq’ÌTôJD8³¶‰ùnKG¬Èè~bŒ†x'’ص{:à ÝdLŸ B@WÍ2wZ¡²Ÿ¨ÊK/yjUÕ×Dùd 8‘˜L¢ÌccÞrW§ô �Î�¸ê÷{ÿe> _D„'¦LŽ“Ì"»ÑiŸ<$‡ËexÅjyA„ŽŸA«©ÀŸ<Oà¦CûJüŒz2"¸a»"`µWQ¥·WÄ(( �„þæ$l!u­Î½¼í¥äT¦ï ²Ëû³GNŠd£{åk›½ïv+íâ¨Ûí<À¢TôÇæøðŒsTZ æGd ̧ÒXHT-@à{`f41&QœA¥§‘°¬••è'·œpÅÒçN®,ßräÐC�ž¼[ç"ŒFQ¶‹¨€SèYNçæÁ`ðãÜE™}Oè£�žDiç;Ùoª³£QEyãJ›’†oN£ž øÚ[÷ˆ Ä>¶p(Eä3 >˜³˜flMDè4ý’Ø¥DM¹D¥ñÀÌh5ë5!T7@3ð3¥ÀöüWœ>¿Éi‰ÌDE»@À+™ÙáÁï ½¾dá±(<—ydFA8,CÊáÇMƒArÅ`Â`¤ CÂ6$3æ»-Œ£›ƒaÉ™‰£Dô®]qág�\ñô3�Þ@¤Æ+¡)¬Êï¬wŸUÖVflŽ2UÝ_ ¦r”~è¿ø6Dz §^?ðän§ó3 þ�7›oœ$ð„`faHÉ|’Ã'îžðÒ hXë2æxžÀ8R„N³añ<’ ¬a[íf€†ï—"HV F4Î<vkͱ*ô›k¥:•tJ–Ld¡µéõ H)´"ô{ùúMÎRJ$‰T÷%ZgÐÝ�þ™3·ˆèŸûýþß»•µcÞÿ]PÓþò}OƸ_ìÉ"\ˆñT™cF…ˆ€°Ý°ŒÓ¦ïLþÕÈ+&Âk·œpÅÓƒ'VÞxÛ ‡O1ã`ÚÖ—zQ©€õ8·ÞS-Ä5Qxî Ua-ãx È[›k†4@J_î8¶3Ô ~ÀOX—�|'}!€;˜ùVÅP&€‰”·f2<O!ýyL�ʨEp ÔãÏgMQÉ/znv•7£Óh– ôR¡h%V­¥­mN;ÁœHÉ·9@£IÌ’9ð‚è—?vïCÿâVÎ%Uþ¯�ð\T@Cm…Uÿ~m*M;%Â\»™¡A2ÃAIåŸ]ÒœY#c�usÀÕB¯ðû¨è¶±ÀÊ[Ì á³5¤»^ÜÁó”éà‹rA–'„•{5èÈB·õ¤•³kŸr,ÛzèäéU�¿Tx9ð‚`!ð¼ëå½ßD„§ A/p›'D¦¼)/›Š•~Dˆã±”|ïV4Žb<÷©wÀóïþè=ð„P“*+Ðù8"ãunAB]—¨"éôƒ4@ŽÒ�ƒ RSÀ�„ã-¿ïá3n¥\Z »Ý§KÈW‘1¾ÏÎêsâ7qG rÄø—Ï>‚(‘ø‚ÛoB"%άod‘ÉD&˜[DØè-£´ ‘"72(n·'®ÐsÈÞzü ‡çÁ|ìà¾ù…tŒ&ùpËg׳IZĽÂþmè<ëêf_M$¬Ã+øÊ }¿øôêù¿vœÛ]ºõèÁ—ѯt$IœÞèÔu.q‡÷-(ÅêQV¨ÅG?ŽTˆ=ðý Hꋞx+ÆQ"`Eð<æ!òPÆbH†õÉÚ³z¥Z¦>º-³ÛD¥&߇ï8¼´€½ó¡^VIêÙ"!è­¯ÿÛúzÇñ]SþK�NJÈU˜Šy£f½÷Ÿ'9[g)ʼnÄ×?ïéˆâÇWN[]%)YëAJµ³¨UŸ#Ž’»<±òeŽs—ž<w .=­®÷ÆK áÆd’¼p4ް8×VÞ¹§ÿøB Ój`®ÓÄXJzôªï{ðƒüïI”`c0Â(Š1Šb '1FéC¿–¶Óxiï¹ïÁ“8ÎŒ€Ê@ŠÄ¡þýfß÷?2žL>븷‹ëd£ÏуK¯‘ÌÈD~MØjrØjÒÆ`‚,t¯‹%36z#Œ£a§™Åü‡£ 6{£LÀ>鿣¸þÀ^\·oA·h)f«õ�,ŸÛ°`…… xž—yü‰”ÊÛA#ÌK ºhAzB@xÝVí¬N!…±ÄÉDòsÿäwÿºãöîQ£Ñx €Û443]˜'˜WI–Â6ÚA€VC=¾ÀfX;ûb0š¨%ÊœTƒ3!%¿zm³÷!ǹKO.°KôÀñ•ß|üõ‡À-B*æv[´Çz”W™;3´ëâ³LÇ$YðÏ+½VôôšÀšß-%@o½óö›ü¾‡W÷v>qÿ±Àÿ¹åÈÁ[ü§Ø¾`ø"ÇÇOÿDˆâ$[ƒá$¬¤…uŠ8¨ø­ŒˆšÕž)0Ý Lk�¾Ào¢ÝÉ#�IJ.•~ôSÌøÂ?ÿû÷—wÕûÿ9�Ï/Š‹"Æ[*žËæ1ÀŒ™Ñð¼LIfŒ&HiCWYu’ˆ%gíË£79Î9àj¤ÿàÿaÛóÙPœ1SKƒñÃI„†‰É½ÂǾŹ „�F“ “Âáüû'<îÈSïý܉رnwéÁ§~ü–ë< ¦¯µ›~…bfllö3á-UV�ª–»üußó2o=-,Í MÎ ‡|íUfõýV‚7E­ÌfY½“/þ³w¾ßtßEêv;OeðUÉ›jTG£�Ö +,…m˜Ý}ÒüÏ‚!ÄVíéh<ÉjH„Þp‚Ñ$€þf¯ÒqÏ�WÝ|ù/ýáwüåMWpù –8 ÂÙó=KQW™iK¡d»G|º—WÚ¾ÄJêÞá¥Åo¹÷s'~ßqo÷‰|ñM­À;X”v÷犟@ /›•›z‰” H™ ‘R|µ>¤j#å4Ÿ«§ûéå$áÈÞyD±ÄÙµ^ÍÕI€“¬û …Ÿ�™$2FÅDD|û>𕎛»®ü÷xŒ4oQéÓ´""äÑ!f†ïçiC)¹ 4‰¾§á«Uz3]Kym“Z³2–Ç±Õ ÝFéùöÿ.’p·`wißbøfœ-︺@-ÖY÷xÏX'8‰®Püq"1Žâ|DlÚ¬­F€fPÃ÷Ñi4~ïk¿â®Vä1 Ž­ôöÌw~¾Õð©Õð™·ô³rР(N0ŽbDq‚H•NvR0"¸G{rÆëBÔŒRæãª‹f«Â0`N&kƒñøÅŽ“»®ü=�oÐÁ¶~·tä+WÝHý[Vï?~Ÿx`ýáÃñƒÉýÉ8[/F**…Jý]ÇA¸jéýŸ¼?þ’;oû·BÐß”¶ë;äU΄  0çQ¤*·#ü_�ß긷ûôÞÝÿªÃ¾ÀMj&�Êvc%ŸË³� ÜûèrÖò%™qôÀb½jù÷\•#V±Þ„U8"ÈDGòëIâ¾ï¯ÿéc§w~À3Œ@Q¥"ç*$küËÛ”U—�éNþȉ ‘Ël¥P¨•‚)Éq"tª6XƒJ~º?¼Ï±o÷ȵ>Fôì§ÝÞð.€ïd¦€@´r~ÓåÊV{õÃ'Îå-63ä݈ªq�R Âу{¬ãÀp<A”Hܰ ­f€Àóžû¦wèçvŸï_|1ý• Õ™X6òµú?²”8ð”ÇÝ€v3Ðýû„Ï-ŸÎf0KsM%ô³ƒ0"E άö”±È IÀ*‚Dh¶ ¼Š(3�RdÁ‹ £÷|ôÞ¶ãÞîRØí¼ „ÿ›)¦J)O�:­²ÿ7‰DIÑnà,­xxq.Cò«šîØM0Gð4¨SžŠäa²h‹è4¥ |ÞÊÙõ{p-�ܰ¶1ø¾(N^6Žb0€á„û”Vxçò¿Ùð3dÁ*’R!ºÕQ Ôj6ÀÌ8¸w.{Oa’$è4$pdîMïþЛ×v—¾á+Ÿá=zzmùÁã§÷{Y H` e!ÀÀÒb¨jˆ ™t„€á ¥ º ”;ÂI"1šÄXß‚õ{Qœ@êOž@«ÕÐ�amc€õþ,ùÍÃáèß:îí¢òïto…÷�ä#ë· �%´» @;‡C][• …½áýñ$C§DaVDXa�è|ìô¹õ/p\Ü]r)€Ç˜Þó±ûN8}ã¡ý·åžc8ŠTO¿á™1·¹"{`ÁÄVĸx,†ã æ:­Ê)ƒÃI_xêlLoúÚç>ã™o~÷‡\î.Ò_¼ãCɳžzë/Ñ«·ûY¡ÂIÚÃ*§ìÒBåÙ™m£±”ºŽ ÉÖ“4Û !1‰’ì;$³Yì‰8Îí¦çßÝÆ=�€«ý;ì¶ü¬X¸²8¸&))ˆ°|¾‡C ¡BýÛè—e†þ?Q§k´¾q¶ÿã¸è €k™¾x'¾¤Ý ÐjY xÙ¶Ü3×ÁÞ…9+VöžÛèáø©UC1�‘LÔf–Àh4!¡ªÈßwóáý/xhùŒв‹t÷¿<ð¿ï_xµÙ¸•h- f|Å*ØBŽÄ–™JÖ� ?œ`MjÏ®– ÒqmWé­�s¯ígkuLWþ\kP =©Ò”)ûíÌ ËBþùÒ‹O[ÿMÇBg�\“tã¡ýÏÚ‰ï `¹é�� �IDATafÌuÛY`"cxBd½øè¶›éÁð|ia£/0ÑH‚醎“$S cýž�&zçÍ×xöC'O¿×qo‰é>0Ýž+l“4”8êÜ–Èc,Èí _@20‰íñÁ“(@H‰I$õhÞ4ÏŸ”æaN±À¦cØîP·Ûù]�_¬‚þ•.yýójAR.NN®m–FAW؉S DÂæ §¸ßã¸è €k™ž¸sJ"âãqTòòl%À•’а…‚pR8ï¼ùº_úÐÉÓ.°[Dø�€Û`Íó£úP®á fí&[9ÅãŒÍªÂ›±¾©æ´'’1Žb¬÷Gª<€ó©ƒY¤€K‹Å�»§ü¿…@ß �›æH˜)ä$Rþâ$ÙöiÓ(1g‰ðFÇIg�\»rhåM/mǪšÞ—$ )ºQñ~#ð5Š'#Ò�ÖF—ŒDUßVRzN®ö!šBÐo>tàù­œþÇÅ]‰�|¢$m5¬o"eQJ[O•»ïênôF¨ ïª5—w¤Œö=DëË“åZÁpí—^ù5€×¡ìâ½íù )ç3ˆZ7vß<®7ŒÒ¿S“âí½þ`ÝqÓ�×,yBtÌçRr¦|c)u!•z÷•õ РfSaü¯÷‡0‡º¦8ј¯Â¯þ|Úr(SÄ.¶Û¥” ÐÛ®Û·ô”“gWïsœ¼Ä$äiÐUí3eé_é‘–pg=‹ïüæ�B° ’ tDBƒCQ&ÕM­’!2Jßò<01 c�gÃ.…ÝÎõ�ÞÈØ"_SP529\£ð«ûìÎN¶^Hþ€ã¦3�®í�0gw9µ¶!„®¨VE7BT@�jƒ Òa8fο°ãk˜Vß÷Ð|û}eˆ“ã8Î&ÚÂA5€¥ygÓøgBcE šÍÛ¢ñøQÇÍKG ÏïÈ&ùUQ’H$f`mcP;ŽÀXŒ!ˆ0×i•…„'0×j`Ç˜Ä ˆxš €Î÷zƒ‰ãØ¥Rþígø( ±í‘˜ÑM „À¾°‹bÏPZ"$ˆ°²vɳ8¯ëõŽ£Î�¸¦iemó~S« !ÀÌXè6´·Eð=¯ pI¼°Š¤µc§×à ‹a&ýS…~fm§W×qôÀ–B#’À¸nß"Žî_Â'Nᣠ5þO¯+@˜C{æŒ^b%P,„-,à £(þ’cËgÇÑK´Y=/J €:’’'\ByF«Â¿¸–FU/2ßi•Çžh5H–êÜµÙæì“tܺTÊ¿ûd€ß°0]sžê¨sÉP+–ö0lØ@«„·2*¦G*¢ L„˜ÿËqÔ�×< Aï1¶üê)lÌÖû @dxî: `ôf£PØcÖ¨ ré! ò!ò/tËC¶‡`$*ñEç62øÒZo8!�͆‡­Úù!à™Õ ¡ª×U€jÚĬ«ø'Ç­K¢ü_àÏ�xVÑîT†NkqÐT›B#—æi¡âáQ’T}ッÁà^ÇUg�\ó´Ñë}f> ¸€^Ñ(¸nß<n8´7óÔ3`½3Ï÷‡8óèŠÈ~KZšƒ Óø>�I8~vÝ /€˜%ÁDøÝnçýþàWwžâ„G�ÐÔuûvRˆ‚÷FµJbûÅâ”Áºe3ÿ`÷”X5w;ní¸òÿ:�o€‰¾%'i[ïQM­@#ð-ŸVš(¹AYi›«ê;Wà(§¿ðï.êt¿ ¥´FÃ’1ïUµ # � IjÃAá¼^@ésr¸jxdff~=„÷w‰+»„4]´o_Ágc¤¥ò³Ú¨ïa[ÌB½^ߥ�vVù/€×^°õvQN°4×±F™áû>Înö ¥ÌàȧÚôÁ~ß ýq€#“Þà%—lƒkÍ̪f`‹¬¡:¾ ®Š$3-„*8¼€Ï1ãI¬œ9æØº£´¿ìï×1o;kƒ²µADjŸä<Ò_@ÊáåÙRzy¸–®Uþ?àd8UŒ·ðþ¹rßßIS}ÅY"̬aÁõþ ß7¢?¹à´MÀ´ Ç ÆXMu¹g�8*ÐÛ œw« Á¡·gK¥_<v'º  ”W&uƒ…ªF@æ>ã?rÓá}_öðòÙ»kẅ;ò¨ŒÏD£Žê Rú> :ß«ÿL †”^Ö ÀL �àAǨSþÿD¯T!:¶u+ÊUü¬f?r%‘BxÖWJfì_ìDØèräÐ%†a^•„Û¯I�orܽ<H¸[pyÐF¯·à5˜VÈ+Ôƒ‰ÑÖü¦rÖ4%èBb 4ãkV”€´f`€Þuã¡}¿õU_òghw{î=Íð(p–s£®’ÝTõýÝâuñÔív_Ç W2›VÝtþÍÂ÷ô?�˜ë4±¶±¶±g®Å¹6–æuk ooa‚¹¶1Äó„ 4†ñü^¯ïZDà¨Âøa�+æöËr³Pó¸¥QýŸZò™žåëY?Íó÷æßæóÙòº<sþ·ÂýžG—×–o»áðMŽÃG’XH0%R"NÕó¯Óì²´Å‹1- Àå(ñ`ë kÉi! ;OsܺÏ?üׂè;…`T×Öq‰öSûýlŸö|·ÝÄBØÆÂ\ s,Îw°g¡òÔi‡£ †£Iíþo6|´>_èsäë"íNò„`Oóïözýw;_>ä¹[pyQ³Ñx!ñ8J(Š%†ã£qŒÑDý;G› H©„¿2­ “8†”ª•o1lƒ%´Rƒrxd…}D– ÉR?ˆXJ] Œ£Ä÷1ˆ!ÒùâM䵆¬ãÄ“IÔM$¿\ÿìh<v³.t³zþ3Áü _|ËÛ°À„Drm[cõ¥DO1û“ó—J¡ô0¾±;™D.Ì{4?øÃ� cäSÊ(¤Ã¬ƒu\xÁh5|øBÀ÷<Oý« ž%6#ÌuZ"•”wÍÀÇ\·…Þ`„À÷¬?A„n»…†ïc4ŽÀÐíÃTµ6ˆ�ôzƒÑó˜9v\¾|È…f/¿(Ào·áð„RE-§VáäÚ&¤dÙ»�f•Kg»KNpÿ£§*Ê6¯”Œ³½LpËLYèùñfnQlj|AV˜˜S5¯Ÿ¯œWSÂ-ΙÞ!¥ø±×í_x­ „çÖ7þ§ãôöéæ#û²;'ÇWÖ Å[æT“2®}§úi~4ƒ¥0 €%ʹެJí¹Ž[L¿BDžd;f“Ý]*æÙÙ†ûe›‰œvý€á8RæE¾·é´º³ÈŠ6j£±Ój`4‰²Ozž(Mé@$xº”Éȱ×�޶¦/ð�€…:).¨…ðêf}g^ƒª�.Ï„WæT1,a€-˜Š²’y {cE<‰“_œÃ;7z½—:6o˜yh pí]UðƒëK•Ž[äý?À7¦»®•o›DDG Z õ F«Ý@«Ù°æB™S&µ3¶Ûf Ñ­ßp³BœàhÆ(À¹ù0ü�ÞZôþ«žæ-X\>Ær÷*¡>²÷xÊQ0ü;k@…°¼¶‰´ÁZlBÄ�¾y> xÁF¯ç¼‚Ù©W% §s õUÿÕoNý‚é¥ ì8tv»ÏK¤|—¹c-㜊&^=Tï,õ:U%„éÇ„Žô¥i&!ÈžBÀ`¬ ¥ÇQŒÁ8† ‚çÕ…ø‡àh{FÀ_χá×øK ¤» Ó‰8ŸÏ^ÉS<¯öžÉƒ,«™²Ñ!„j ³Bœõ§²åy�>3†Ûèõœæ˜6§ñ¢ hZ}ãTá¼Sõ) 2Ÿ g�\×?×`æ·K–Ï©Ñ)ÔW¨B>‹¶×]Öÿ45Fd¦‘<A¸çá“ù(pfì]œ+Y Yô‰t-U­G"ßµz¾wãôåI® àò6Þàg‘§ýجӪVÏÕm?TÛ6D€õ)šêáQ¡•3øS‚ 7xt> :nÏDýjŽÏÐã9õimeÕ…åQ2[žÄQö,Ìýp’$g¥”Ï3ÌešeûdÿQ‘/yA/•¦zÕsnz‚ôCdh‰”ˆb‰D2FQ„ád’=f@üc$@?â8í"�Ž.ÜøÉùnø‡ þKÎ^VlÇgÑ›Ÿ:ªK©õ‚·~J}fÒ×™~íu�˜ëv—6ûýÈq|ê}ëUÈñ£ØvK¤y UL˜Î=}ªx*Ž«2ÕÑÒâBàÓÌò†íß4.ðØôÊi˲qìp#‘÷;Ï## *­z"}˜:ú/‡%¨:¦O8Ž;ÀÑÅýÞósá~fþqfþ ¯²:yn3“ Zu˜ Gi«w$òBž Í‹¹$�¤µç« ŠY`Ò)söfÉx€g:nOcmæs 94+Uå~¬ém\Ë»²1G?ÓÊæ²)B¼œ½þç1Ë7� ÔÉóé\Sæ.¤­µ¤‹l™Š¬Oûûiêv¯ÓÝ\sn"dé€"tp:U4m#•2Ã#€ŽøÚÕó›®íÏ�Ž.ÚØìÅ�~¶Ûíœgà×SÊ”—ï � Ë‚ð¨Þñ²àšP㢠%2ð!] X9ýì4‰äiÊ«N-Tg´Ûíw ‡Ã¯tÜ®&)¹Ÿ xJ¸Bçæ € ½Xù (»m,m×LÛûÒó¥a´2ÇUµ�fWêB�txÿÒwǓק7ÑóDjç³�Ü3—1"em¡?žTNÞ“¬öi•‚‰Þ°ús B_÷ñϵ‚’a'áôê:ÀŒý{2' Ž/¯)ƒDäR(s>~cõü¦Ëý_îN…»Wu»ðùS{Æà)á‰K™d¢à¡[BAaˆ«s,v[|/[H§Öûô{ô9R-ò'ƒÁàß;.—©Óé$ÂJ•ž"¼eíY5�* €\±{B€ sრiá�ýSa<Iú�íëõcÇ5EwÞ~Ó›„ ¯}èÄ&ÒÍõ†K>‰âŒÌŒƒ‹¡Å[!< ÇôFùwÝlŸÌ†3{ g€a…­)fìß»A© q|eU¯5aÅ}T0îÙì >ÏqÞE�í41ÿ j €,$UþÛ Ë`*+ÿ¢¢©þ,xÂA<KZ@ãæCΙ_†Ý/nøÞ‹VÏo|Ê1ÛòÆzö«5¦ªî²•mÎù˜z÷È„9¡á©b°(I`p§’§…ÈÁ‡ªíxèZçÙwd¿ïyoð,­qí¹} }_ìë@²Ý‘bldc½+"lEæ”jyhÊ€¨ÒzÉ ÉÍA"`ãÑ3Vÿ¿ThGVíÜàvì SÜ-¸Ã6$Þ£BÓ‡½i+~® ÝÓŒæ ìñô•ì+‹Ý6öèGày3‹ë¡"7Ž£øcaØý5ÇmëŽ%È�[ç\À׿æõÁ¬Mú</{ÆwÜÓmc®ÝÒ9¦ª.�s=Úøï�m�\ÓtÇ-GŸHD÷Jæg!ϲY7-méK•õRØÖÆ3ïi¥M—ϱ! ™Ùâ±/UɃª½ž7$˜]‚òn4ˆsæ¥sHÌôA·_]ÀÑ¥±�ÞQ2ÕÓ·¸¤¢1K¦gZQ×”N¢Ò±Ûþ)åRÀ†a÷é�þS¯×ÿ´c|µ—–ݶiÃáLƒóŠîv3(Œ”•:"ó¯ƒrÀƒš ø¾kXù€ÿmßD¶<sžê©Û÷¶Š§R2®Û7Ÿ)þ8I°²šÃ{W¥ äEüD„Íad#AÔDX;yk²eß8ðg�8ºÔëõ–Ã0|ªþª5s´Ôyƒ?†Ý—ôzýÿ縿ƒ&óV¡S$@jÂàÅÑ¿ð‡×Ú=}â­G2ã=�n.Zj¾ç¡Ýl”Í8"¬÷³Ù|’i@ˆžðàk<þZ“‘fÛxu-…y4PÔY¤'|~¿ß?åvØåO.p¥2Žð#G<BÃÅ9ƒ]!à ëÜ¢­ÔvZõˆ¼q. _î8?kÄ¥Ô#õ£ê¦KãAÛ;Mæñ©u¤ ܘé©×7ºÝî\·ÛyÍzotŒ™o^ ;|pÏ.ÍÓ¡¥y\šÇá}‹0z@yˆ=󴉊;$‚ÀÇâ\ÝfÝ–z„¦Jß‘Ý~ISjêùôG1zÃÈðøíTAÑ(ÐH€ijàÿÄŒ§ü]ÀÑ%¥vÃ{ ÈÆS�ðx’TõøLW´µPÈ­þÜ%·§”=Ã’¨¼fª‹üê\¾w³×û¨Súu·©Î²ªK …Ù}‚¼à,œÝ-йV¸Òét^ÈÌo Ò 1ßiÓ|· ºG¾ï¡ÕtIEìYÜli±_–W‡*¶ó|UœÙnÚ•ú3%øh;/“]œ³µ•IP©žg÷z7Ê�ŽvƒN[î]x)3JÚ–æõDžpE!™ BØnX9Jf J�@« ícN‰8J.ÌØžö{ï ‡öÜvleí„[ ͵|ëƒÑ4쇫�f~.ìøžøÛ¦ï?;Ý÷ÌÓþ=s˜ï¶àë½áy„f3€?CalJF�³{#NdÖr+êZõv—ÒA?ÿÔë ¾ÔíŠ+“\ àÊ6>MDßÕÆZÌóã¬qÓ�H=T¨4ÍÀ/=Zß÷àyú!Deñ´G§Êfut…Ã'üÛŽûÀ´jîéþek€,h`{Ú‹ÊÏá{ ßÓ³â¹Ô%¢Ós5ßùn§óyÌ|’€g·>·>šOÝv aG){£ûRJ )uµ¾ÌßH÷¬§§î¥7Ý÷D¾·|oj+nÕ¾³b;ˆÍ\õ°ÖTñær#0ƒôšù7n^¹ä€€®Ú·gþ-zñpodÝw̤ZÁJö¼nVJ!>=!øæÚÍZ#¢© ›L¹Å $3Æã¨\Ÿå<³Ë£ÉAÒÊEúL(ÔÁ—õúýß¿–ø†Ý€aÙ�HïŽ(¼NS×�´’}óÝ “ˆÐj`fDI¬£;1Ò‰BR€P’ç6‡`N²5@ æ+{½á?\|xÒãoø/QÿÌx5ˆ}_ˆÀ’á{ªï†Cû0¶3˜Þ”G’¾'ð÷¼‚ûºz/©¶º8Ž1‰b„ÝV¥W/¥„'†ÃIÉ( "ÄI)%V7‡�Hu K% YªâÁRF‰a1¦1YÝ"Ú|ü¹Á ÿÿ9 |å’K\tvmãkî]ü0€/ØJò׆ ð 6z )áÕ »²dOès°¼DÄ Xra†qn�˜¯ç³<Õ:• &¢×ÞphÏ›­¬w6üÖŸl¼«9 ˆXæÊÀlTB)¤€´§ŸÈ ñ-UžlNž é„ €¯¶;}Ó¡½]ß~ßøËX¶~E'ˆ¢8›{a¶Ç13Ã6ßW°½é>a`'Vä­næŽ0"mUȾçe@Ìl÷riHæÛ”¿VUb•P„k°ËÃ�Ž.Kjøâ«ûÀ2®‘´ºQÂÿÀ_ClŽíxÍì”B¸\˜³ä©’N§¹å0™mX$“^oððÕtãÓu‹­ ¸Àa1«ømäÞ}ÏÃßÞ­À-¯[ZÐ _½×ŽÖFU:uo ^A8µ¶i× e$Ib]AjÃä"kuÀCƒ~ÿ~'y¯lr5�W ?µz†™oÐ`Wí•\­Êê±aed²m̧­O¿ec[^?"ÕüÐáý‹_s­ð¸×ëÇP}ÖT}÷*Ð|p>l¦8GÞ†œ¥ºuc$‚ÍuP¯yÛÕtßo¿ùÈKÑ*N7sá–Àè!ÀóüÂ#ð=ĉDœ¨0~¥K…v>TòÐ0~³b].¦ç §?›ê©™Ê0 ½ [·ÜPÂVοxE|“º.àè2¢þ`ð`†/ðžZåo‘©³ASíÀ²ö™ÛŒ©¾A­Î„  !ØløUïï_|Âò™ó×JWÀøÑr¯V1¸KV=?°fèié_6¹]{¢\ð uƒ_uó 1@H1Õô%ä\ 7úŽ[Ž �¿ODÿ!­°¥ŠÎ˸%‚�ãƒ÷<ˆQ”Øc˜$ÚpjúؘÜ9-’@DÇÙ±¾ðpjmSÁó Ê €Óë‹e~Fsô³5ë#18Íê–•è’ oìõûnÒŸ3�]~^bï½a¾™ÿ&Ó5Q�SøDqO$ƒ ÕaI3\Y4L%}ÁíHÏé] ŒD2|æ†Ã{íºý‹¿Æ>�O9µºqçh]Æ ¼À?,Ÿ=?º Xüze�\èíÝ™ºßZ¸Y�½ÞàíWúM^;×Ñ<SR.\´”ÇRŽÀlMn6Fjc¶Bé^k¾Þ¯úL9Kµ7ëÓô½VÖýé=ø¶^¿ÿF'iàèò5Þ¶ïžðËuQ�¢¼Ÿ?IÏûüÇçð¯DºeIÍObœï aNô )1Œáû ªªôî3‡Õö^}_A›…”YìtË‘½Ð©ÒÌÿM2þÙÐrjí[üg�ßàž•+ÖàOCÕø[ßéê·È(ø,*(¶ªÏ¸ÂØcŒ¢±ÌÌWM?Ñ¡}‹m�O“’ÿM.Mð³§÷ O Õ ¬=A�QŒXÊ2;b‰­bgD„ñ8ªÜ³Ì€äDíO³ ³24¡¨øXì´²½µ9c8‰¬H€ïyÖïJ¤,@D1xy¿?x½“°W¹€«”Μ[{¤ünSvg÷`–FB?Õ“„8‘HâI’ Ñ-`RªÞeÉE¯‚3¥Pj” ¢RiÓév"¶r˜êC”M¬õr @ ÈÄ’@ùd=]Rš“Õ°k_à#�î;´oñ§¯P��ûõh…‡¾Ù"EëcòÀj¢¤H'¼îpBf‹{DœÁÿ‚`„¡ù쫇÷/î9´oñw�|–™ßp‹4ek”÷¬&â©ð»0¦oš5%³1;Ÿw)¥Ô©'^Vþ©>·é}W;'‹3ˆt¨™’:½cä+Bê6@G¶÷1 eþHËlXÀø¶~ðëN²^]äp�®rÚ·gá׈è­® î;³êçŽã à‹Ÿ|+â$ΔmŠô¦°Â'ØŒ-a• —8N01¼«ã“q¥!�A90J…Bk7=¼²”’Ñn¸ñà’í«€µp8~jQœ÷¨ëß«£¯A…ÓÿüÌêúÊ•ÀÏ0ì<À?ç}Z¦·^ÆòO«É=Í«ÃKó–·hó‘ ´[$3†ƒ±>,O&q5"²£â‚냉~6ñz½è²‡…ív;MÉ|gØ ^àÒn=O¨Â ©ø}‹4ï±åsð<e|¶>–çlCU0šA�"àÄ©õlýeQ,@{àj´n»é—Ì8Oi¶‚ 2Mày_œ8·©Œ7ƒ¡¬÷a±ÛÒ)=ÎökV� ™~ÖuPÕ^¨÷ÿÏöúýŸtÒÔE�]atvmýå�~²26h%ß÷tï>W֦ЂˆJsç‹^ºu ¡ò½tƼ)XëÎY&õ<*ä´:z4‰,ákTO) �øU�÷\ZxíÂүߖ…o`4 ’g)4è“Ðíg0/v Tð>3¹,>ùG¯�åÿã�"àn¾A{ï™Uì!èKï‘"«â'AÙô¼´Ã"]×R–#"*À0±ú*¯jö eûÙàÃíÐ=Ûµ¹’Ÿ]“Úó'àœò¿zÉÕ�\tfõüÏî_Z8Ðw#‹÷—gާÒ+1 ¹Ï =‘}Ž’à«Œ  T©ž*¡Tp³Ž($ºå*‘ŒÑ$)æ×t‰ðýNû;ˆèü§ƒþð³—);ÿ]ñ—oÐS•áê¸ãg7*¹A¤¼Îƒ{Bìª}+—¾+µ—+»^oxìr¼qív療ðR�ß®”}d*ÄA"`ãѳH!ªÓhGÂ\©p­nL²­dÆ­×€”Œqƒ 3×6úð<ÀËý±DC×EÆŠý|Á›°¼‚ì™#0^ýÙãË¿á$¨‹�8ºâ€õïa«µ££kzò¬až¾Õ°¤%/œ°1ïŒò7¼K°ì«*!¹ÐËQÿ?¿9ħ>w gוQŠ,çZð¦´GEDÄDÔðSº'ìvßv»·^N< ÃN  ›ó_ŸùU‘¡r·YýD9Š"AÊsÙTœOÖƒJãa…B$a–É]ví˜NçNç�ãå`ø¥aÙàic}é:O�žöú=Ý[/ˆ2¸ìRXÈrëÖl �Ÿ;q6Ÿ  sñ¶ΚöógØÿTèé`Ô�@Ó”‡ `½Pò"üSŸ=¾ü#Nrº€£«Å8wþGì]@¯(á€SâͲFú:U·ñ´<þÅ“”Œ„e^yο… ±Ô+g7°|vݾ>äi­ý!�€àù�î»]H`LÀ�üR¿ß Anèóª.›™õ„G xhøå©s‰T h³€!Ánc­kJw_k½ÛíÞàÛ™ù›É­@û/" XqO¤‹%Mãi{ë{1l¡Ùðá{Âè˜Pi–œ Ï’BÁOèI*Wo†ü ¡ º¤`å¥Ïœ�� �IDAT?r+>Kf^š3»CÒÚ˜×Üwlù§Ät€£«ŒNŸ;ÿ#û—žà_A×û°¡POžÛ„4À¤Ìó”Ÿ{ô,t}”-HÀh>æ³V£íG2Ä:.+ÿÇ_¿ýq\o¦žŒ&1>~ÿɬ° ¤z�s`Õb̦ ¹ àÙ�žÓív>àßôûÔ-?qªR®sÈζÏXTùú…´Z=÷–³?ßû˜(üNG�hùLô Ì|k…æ¦êõGÛ´s`{è5o3CwÐäûÉÓu¹ ÕkTš4z`Îs .Nk,_œã¯ú‰ù¾`fÖè¿óÀñåt’Ò�Ž®RŠ“øë˜Å "“(¶ ’âD"Ñ}Æ�x^&ìÓb/Ϙ"˜ª•L§F¹N–2+Æ£<¬Zò\‰Iœ€@HXZÂ2!g  ¥·)­í¶º¬—‹<ÀÝnççûýÁ.GñÁ²–"Õ×)Í›_”ô¬ÊÛ¦M ÔZ¼¾›\ó’óaÍF`)"æóý3à­»yGÂn·ÉÌßUy'ˆBÎ-Ú4¿³Ã˜ü枇ómû^1eØ�‚žç]ÐIˆ€ÕÞ0óüɰ²˜€„e!u›äuToïB·dè"œ]íø‚Éÿûþã+ßã$¤3�]Å´¶Þ_Ù³0÷4�KõbZ)üࣧAD¸ñð’r”ÌxüõÀ`<ôè¹R$`8‰0˜Dhú¾À,žVú4ý®^ÖFf+ŒóÇNƒA¸åÈþRås«àæ£ûÐŒqö|¯Ò›Ûùo•( �?ÑívÞÒï>¼›¶[-¨²¾<† ÷ QíÙ¦-c‰¬FmŒuë[»óÒïV핞'*Ðä˜|O¬œ_ï]òÈH§ÛÞ+XÜÂxAé†PE•ëÌ!Ž­©áûùÀ<Aˆ©;*È2”�ààRˆÓk}Uˆ™È‚¼µ*„êM\mƒ¤mžTHü{:Ê ¢h²íbfH�¾/XYHüÆû¯|·“ŽÎ�ptM›ŸØ³0ÿ_ßû³d&)¥5nHû€•àWʵÁF€2èÐÊP#ðÊÙ–¿R&Miz õ/J¸6 ËÌÕ-Q—Ž€ÇŒ·�¸nO»X÷NŠÛ6‰L¢í–ß3ûôÕ¿Ýf�ac8)Ecf¬ö†hîxÜáLq ¸µÞ�£IlŸŸ7ZzÍùõÞŽüÒ[ÜODÏð4ÝÚ¾)ž¼²¶ù�öÇ1ï%mê1M˜¶ÿÁÃû-{cc0B»`®ÓÒhŠ Caöì[è€�,+o[¯k/¬Â”uÝÖèš½QT% ÊŹ7ìBù{}Ýq°w1$�r÷'îÿ÷N*:ÀÑ5elüâž…ð˜^Î’!%8oß§<ç¨ÿ¨[=*¦Œ KN×´ç•Q¶+ÐkÞž:%óß‚+¸µgÈ�‡aç{{½ÁoíË®«¶Fr> ùx.* ¥˜À„v«‘çóÚðšãM·Þ˜Å…ôúÅFZ°ó´°Õü±v#x ‰R)C–«"2Î^1È®º¸ÃÄ.2@#k•¯º9yZi‰„…˜­i®ZãŒIgë.Idõn -6†×!¥}­Ö\Èl´°¹¨ à�üSþÎ�ptͽÚ3?÷W‰”ïÚ^²tÆ+9† >{júI /½±­ë¦Ò,÷Ä:Õ ‘áôío ÃÎo÷zƒm‡ ºÝn£ßïO¶á¯>ÇÆX¤­o™þ±‰.D‹%C&;´¤ê< °'ÔèÚ|½0¨„=[μ�^ àç/Lù·_à™9п.O>P^—¾È…fš¦4Í«.L­+e:-ë<ݹvv7˜M™òK.NÏ­–4fo¥¶± gÜcdá Æb·™áu0„J½ 0àýwâþí¤ 3�]ËFÀÆæ]Nç�€Wø�‹3ûÁ3zÙÓDØNÐp4ÙÑ{²}€9�ÂNØíÞ !¿€@OgægÑDtÄö ÝnÇ<Ûi€?5Îù-ýþà>í�ðG�nÛò¢YyôqbÉHæB½" 3„d,¦™}虿ûEwÞ~ÓÓ?~ßÃ[ÖE„aw�ÑëõO‡açÛ~Å4ÔêW¡è]ÀúdftšAþ‹Œûe©2¢b•×E¹a»ÞªP¿>n4™d©2*úͨÃì68Mµû¬¯!Bà{éwk‰ÏÑ œôs€#G g�|+�ÌÏ…_ÊÀO1óó —{¦¢¥ QTzJÛü˜ùsYC "ôGcx5SìjÜbãûê«ßgÇû�t°½É,�¼ÀhןÛÔ¦Väâ�€x€_êt: ˜Íj­XT „„”™$Õ?½xÆuÌš>×­”ÓŽ*N'º À€H/zÚ Íøz€¾ Às `˜†íz®+U…´³ Nȳ)FÞ:ä�f£r*fÖÖQ"ÂêÆ@ßïÔHOiÝ›e̾2K+­VM�øÂ÷âþóNò9À‘#‹66{ïÝØì}ù¾0ì´ÛÍ;IЂ^˜ƒÎ«–‰P—+))«#TVET¿ldaA >|bµä5¥ºÇj åyTQD4¼-ia Ù)&š5âx€'�¸•sŸ˜óZùüžä70¿Wv¾Ñ̨~R³Ê©+á&ÜêX§Ìæu™ÿºB%gw•A:5b:ÿ½áëýaU QØí¶%¢¿ÐJþñ�ÝðáÜ7.þrù(뉃½Ñ8MmëåZ\dÆ¡Óxi¯Cõ<0Ú÷˜YM¯, +F±ÄF!&QÇZ“Då_:.O‚l¬Ô ’*(`šÅJU€®nôô²& |~ðчœ¤sä �Gµt¶× ×{?€ÝtxÿÑ,ôX—„S kÍL'r’e‘–ȼ8*£eT)ú³³Uà×ÛÏʃ¨Â Ø†÷ŸÒ‹ŠŸáš_K¨ê\+à ^ÛÒô¡ dE›c<‰ÑŒ­ûV€ÚðL¤ MúŒ£±LÀf‰óô ¯Pî;•n²°&HµØ©{4u˜=KÔxúy”!_{ÅМpÁ�¨¾U)¤ˆˆûÃ1˜™„ï8qzõ—tsä �G3ÓÃËg¾õæë¼ ÀŸM;.ð}´›AA•©‘ÃQœ ‘ÉájN')¨P¦JoVa·ó–zNÛ¹R9 lk<FtY\Àêæ öýÍÑ“¸ÈGcºÕ ÔlIÃIŒIœÀR/rôFM6ÜÎïÙ©šfÆÊ¹ (D¿ºP~jÌúRd@Yã(®ÍñljÄ$68yz–¿<Z› 5P¡7šä£›Ah7<"¢ÿ|âôêk4sä �GÛ¦‡NžþóïÿLàyQ"3ï.Í1&‰Ä$JàgxœÏ"°Æ¨¢ÔÃO©;ÐÍÈœƒ&r‡ÇB°“%×à ¡‡å°©0§ä°‚@fª  `ús»á« Ô¹NÙÏb p èh«ÏU»Æ”ö§ßgâÈk¶¬à NжTJù *aQí¨¾t©ÇèJÁà<mþàJè[&EÀ©*°œŠ¯*øÓi<Q“üRì "20*”satv•ÀÌsC§ŒõÉ�f1"Xë±Ðie7"‘éì @·ØûŽå³kw9)æ—…›á芥Ûo¸n~Ç;·Ñ\*ˆRd¹Tø-tZh¾†ûE&Ü�`GY[Z•`ì £ !Yîe®Ö„ÒîÌ@3ð0ßi!Ndæ•?£?ŽÚÅ^†y!§l&bm­tùu a(-Y È'Ë¥ @L<£òWŸWEißóÀÌØ·ºíe·šAI¡¢ÌÀÙµ&“¤|n”J¹)ymFO•ªåãš½{5— �aÖ0 IX ö¥å§`ÝþÈØ;ßUJµ7´¢R©A›"ú™àUã(†'„¾§ÝlMž—µ)JÝý1O,.3€Â$VŠ[E¬$�m\ <ÕQ2ãàBˆDÊlX—”òׇã$‘·3ðq€ßÈ,Îý¡“\Ž\ÀÑEÓ}ÇNn�¸e~.|#»5BVÐüJ5Vçýï^;h5y?µöœ|áåó ô5ÔŸoëë¨÷$§´¤Õ>™¥’ÝÁ[Ów6cEšWŽ9ÉЙ¹òjS¥kÇ¡ÊHÒŠNÔF¶º¿4㺘2Û ætÕH•ª—?‘¬ÝJ©kZ׿©×$Me®×˜94É#š÷[tÈ=K=ÿs›ìë†xçúFï]NJ9r€£KJ›½—ÌÏ…?Ư©ZòÄü1êÓð~±€yzk[¥÷XaY¤ ~±Û‚ÔcÌΦ¦©±‡ŠLeO—­H«™©rJ hfŸ¸dX0×+2ó«"D„8QJ3ð=é ¶<m¡½ÿz%”FªìÉŒƒ‹!ÀÊzOÓºÚÌ��±®éÀŒ7Ø„öÃÔÿ*ÜÀªúJpf½Ÿ)ÙT‘{ZùÎ 9-á´1›Â ¶‚‚â×{ƒëï¹ Õp@G¨þn~ÄI&GÎ�p´[FÀ¯ÎÏ…'ºÍàõÃñ¤™u�d“÷Ì2û;E­—Zd ±…3lÈ6fRÇûµÒF:Ýj(e&’–6M§2òV¿LíeuœõŸÙa1 à g?ÕÖ,”Ϙ·Â¹Ä:O]è³=ÁP²Ý0(“BØÝPôÕ)ÕZ§ÎŸèk…cÓ\¶(RÓ$2¼hÈ´åRE«Á¦Ó¯ÕÂ=îQZȖϧ¯©a@È‚Æwê@„ðL7½ =eA𣣷6Fråæ„ÐõYñ¡ÉðÒ@,JɆ»f#D‘ÕÅVDŒ6‹w>¼|fÝI%GÎ�p´›FÀXv"Â�öL45³xÊxÛ«Êε½ Qá&ì’AÇR½ ¯ Âs]mc„p±‘«¿ÏŽ&L1bf̵¥kH¤ÄpcëùwTqq<åâ«oÐë0G˜k6°Ðn•¾'jÂÿ[\š¡äÒß¼w®“að›óÊÚ¦**M?û-~Κ™v¹R2dЇPs §ÎoZž½©ìc™ NŒ ‘áåONÔ­fã½ÂI#GÎ�p´ë´Ùïø¦#þ½Œ�4q,±¶1°JF­„Rå «È�ã�œïÁPEˆEEæyM 0‰b˳L£s&ˆë½á¶™)nö_f·*r1m æ¡ ¨éDP•÷d)£üQT¤dx¸©¢.v¦3òz±Íëâ|êOåD;†Š4HbW½•}2…¡©aH4ýx³F&íh0 _g�6ìD£–…Üóðò™O:Iäh[kÛÝG;EO¾íú®ddó`'Q‚å3ëvY!»€tŒ©Ùe†ÈSo�ì[èênÙ£E1â ¬ÜN³A„Sç{Ö…PázgÐØºÔ/ýM‚ê½÷´ˆŒ˜ë:ÅÁ%¥'£(ÎŒ�"ªÝéæ8X© ß®[ZÈfH©òàD*/ï ¡°ô½TÅq¹‡Ûi4¬ž*¶8‘ AXYÝ4 ‰ ‹É †/øyȾj¶½Yx¨» ;½ªGXO»¿¢ÖBK+è/ÖÈ#šaàÒº!"t›ÉNâR¡:!³:(í6`Ýéú/Ÿù '…¹€£Ç„>ùÙãý;n9ú €[Rá+™a§ùmOõ‚¼ål,Íp ÐjØ3ßÍ^]]ïa°Åð Ú!F[ à3#» À†Îͯ± Ú¸ü·Ý ^ŒXj·Ñ >/ HdÕBØm†Y$ MåÈ´ž@y±Ó§¬¨sÄá cˆ¨Übyü a"C–”yƒÉH×ÇU׊qÖ ÏT†Ö§œòµšÖ“ØY"®©Û(“'ÈZ¬,Ü»^9딿#g�8zÌéÃ�5qLy¬FKØÅ´û¥^%™[Rˆ¦×l(††1/½˜D‰L*=å´{áB®uZ­@ý×ͼgVÀJiX=I¤F¦­£)é}„¾‰sZA%¹2KtÑ™'EqÞq¡ãÿêÜ5þÌhø^ž¯ HxB ÝôK¯ ²'„( þYmð=u $ë€KìÜVɃ6|zÃIV@hvP Ç%�äûÞ£·ß|èk­œu’Ç‘3�=ÆÄx;ß�ïá†C‹ŽcœK[¢¶ƒÇJ5k ]2phq. g§Îrà{8¸w±$L—ºØ3ßÁɳç1‰’’'·±›¥¶SÌÆ¼·§šTÈ›$•ÕU4{B‚ Ú”*\õå`ˆlçý‹Æ…ݲW,üܾÂåª>{ªN¥¨cIáÐŽ^ì ¥ƒŠa“·ÅY�D\´O&‰¼ãoßûñž<Ž.hº[àh§éŽÇ=ÂRú|8šàÌZOÉ,1ã—ZϬ09S6g]ªfvÝ·áåP¿Q,á{‡÷-Ô*š“gÎcŵ^ÚÊj/Ç/àòâ¢òŸÖ"ÈS†×ëìI`˜kç}äi ýúI”d0¾):?Q±¯_Ø÷¢ˆVl´(˜×Õð=4üt¾=kåLÙˆ£n³!'ÏmX^»LØjw³z¤ª<V÷®Ë4Rº­åJÿð…,ºã ‡ï=fÈQ©s¡ŽÒ€r^zia /Œ-L­âkRÚ T1YÓ4�LÃàО93=òæ$áo<~êìÄIG.àèr2+Ÿ à>¨Q¹_¤]Èï¦úJJÆuKs•µÓB Eï—·¨'`fXèUòÀÊZ¯Ò¸Žh•WÍÆÉŠUó™™áÆì}U÷¢Ì‡l´³Y7kàDáZå”i‹Å.Èé„üd¬ !¥”�‹)‘‰ízæùo°GBKçLÎêSMo,Ë\íaf&�?öÈÉ3¯r‚Æ‘3�]vô™}ð ;ò|"º‹ Û¶„òÌÜ(Ò)Œ rè_C9¾‡À÷jsò)¢]œHÄI’åÖM_jï8msÛR™î°ò7óÂæk›Ã¨âXi)Ž¢‚¥‹¼“ÆQ‚(ÉñõÓïÞN2³”³óXq ¥Í�Lbĉć÷Zµi4Äó„ …= H÷ìï´=ûØ3phOf&Éü6"zÅ#ËgîuRÆ‘3�]¶tïçN¼À\§Ý~Ý)„VÅ,Èr·ëùBW†S:±'±ñÊÞãlC‚§ÖòTªdÆÑ½óÆ –­•¿©óŠaým‡<P‡[_•§Ú*xs~NµBãÚpy¨¤;ÌÞþRD†)ò “J¡u®aÄYd+¢RU“–nŠªCÁ#‚'"NÊ·’꙼°±Š \ˆBMùÞ)†Bu÷ÇlÊ_MÀäuf|ﱕ³ê$‹#g�8ºR¨7?? »_àm�Ûu§BÐÆÿY#²V¾ÔŠªžàg´é¥!k�GJUažHF””縫´,µvZív•8’ŠBpb婊Ea˜÷¤0`ˆÉª°L”0¢8FÕL†¢ÄFž„�â ˜¦/&±¬E,¥‚ ö²Œž*~Ö[Aµ¢m¯Üž)¦€VñVŠ<;ßì .Áøõ–üô½ÇN®:qâh§É:Ú îðÝ€xfî0MŸ ÏÌðD}Eyê—’qxß|Iñ23ÆQb(œ¢@WÒxemSª-Md#Ž%ö͇ÿ{ç#[v•÷oísNUwUõ}ͽ3wÆÆ€q"äA@˜ ‚B„€HQ^DQ€Dù#!$A€J„È[B&â©ØŠˆâ˜(6`ÀÄÄØc;`ŒÇØÏŒçåyÞ™;Ó÷ÑÝõ®sÎ^ùcïsÎ>ªî™é;s»çûjnwWSÕûtÕúöÚk ÚðË/·â‰à¹ëãVé*ì+ÖÌ›E}E€a†D¥&xÖͬÛ-ŒÛ÷ÕÖ¼U–—ím!aY^Tû=µ,’S˜¢ðÒæ¾;J fD¶Z¡_£8RU;ÅZdIl`­"ktűªxÓça¸xÎù9„ëñF=yÆæËyVúe5¤¹ÚšwÂrû±‹MõEá_qŽCjEŠ¡»n-¾>Ÿý.?=È­"âWƒÕ*ÕÕ*}g¯×3�¾G,4"è̼úOÐ$Ž �v[åä¹¼ùm‡ÎÀ5ªÏR] Y¥9ŒTÏ®¡o÷{ó¿Í îörûžíž/Í WTº'±Aäy—�hÎæ¥6ÛT ý:æ­²n>ê*õ/žb{+Ád±ªú„Á²ÙPµQ(¨å ¹.FÚ-Ë.ŒÒl¶S¿ô.{ Î› Ü_oš´7™ãÆx†7^:[ÿ;ðd¹b»ßÃx¶„n(ÄoÖT¼Ôýûí?ÄÎo;áŸS�<¢Š¯™ÏgŸã'¹•p €¼ªL&“= ð�ƒ`ú¹ù“7,l«yÏ»µç网M-°�H³ ½8¹Ñ6�Õv:¿êëv½D¤s¦g­Å[¾äRmßöþtå2Ã2MË_a]º¹-êR¶¾ƒ¨T)zmÚ(»™|ÇèŬ whMð”ÕûŒâûæzIÐe¯l;×0÷8T3J1[»”Q$µÙq% 6į́߿X¤õ?@÷hãâI(àjø°?½ÀÝ°ÌÆ S9Bø¯ž§kË_«"Cõ—f³ùñ“‚P�S*fï†ÿÀÿðÖMŸ ¶\ h×(€Õ*;D;HÍA°=;sÞö¥'I»ÇùþZ›U»ª5k«^ñªŠÑv£íö¦åë(Ü÷ÿ5‚z·#R÷€ ¶z83ÜÆj•–Å‘…÷¿ˆ`•eXkË×:±nx\+÷Ðqœéà£ÔNˆ×…¯ÁþxQ ¨å„JÕZW‚àÄÛZØÖM]ë•“ª1³4í›»×ÜËÐ ZÊæ¯Ìf³{ù A^-X@^SF£áßð³€^nåTµš‡Ö¿µ"2mÌ1§¨dϬÅv?Áh«ß�FÆ\ÛŸv…U‹oýº·¶+ÈQyæ?ð䳈j‹ÄNx,W+ä¹Å*uÛÙB“åNx¤ aPóÿoí l¬G£A¿|mý$A/quªŠÌ×@„ 2Óå Fãù²>Ó¶áÓéÑ» 6S#APß´Îã¸ï;Ü�ƒkqéܪÎt¨v ý“Lf ä8˜/Ë!3Á‹sý‚"ÒÎTíb´ÎÓ¬hƺ U_Zx?€ïN§ò0@^Gـ黼{4þ2`ÿ€^u‚Ï×UºyöœDQó3ºô (·êk] åPÎ,Õ¥ý]'6'2zqýmcDÐO’vçyUloõ±JS¬üR@8û+DM3;Q³^cjS<&2‚Aß=¿Vs(€ÜÒ<³­âAÀPà`¶Ü¸&-¨§½×‹°µ ê=Œ›ûµ™³@ÖÌ”Ý8_ߟ!·£Ë|@}yc°ÕC–+æ‹J=®­]42ûhlh(š` ¥³é‚®9ÏúáUÅg³éwð“€P�׳øÇ£Ñö/�òv¾ Ë›Z¾v}ÖÖ{À(6í:HâoýòËhmRGQg ÈU;óÔ¡?}½Àìð´wóë°¾AT°)]_ÌРàÐ )Úýƹ_gé{¥å°ÆÄI˜zV¦–¤Ñnà²ëÓã‡. �È2ÛyŸ¨–é~ ºïEµWoµ9;×Î5“oŸÇ‘*Œüï*ƒ4›MßÉw?¡� “ù�¾}4|€·¸ëHJ©_Ÿ"ÓZË�½8Aâÿ:@¢X¦¶z1z½¸%0ýžó�°X¥Á=‰¢²ž ³˜Päð9av¥[컊sš#ˆŽ"°š²Sâ1²¡u²nèÂûJü´áø×2H*ÔŸ„ãªG|ù›Fè°û-U\Á_ÍæŸâ»žP�R³_¿£ŠÁ¿ëœJµ‚ˆlœÝŸncºXâÆxÖù˜sàÜÎ`}ÀA½W}W‚WUSŠ‘æë´V‘æyicÜGp‡M¿Qdb\bE¾H±x=ÆŸÃv¦ëÓ<ƒãÌ:+ÓqHíÞÑ ûn%Ár•ÁªÛõ��צÐZ?‚Ìâµ®v ÿvÀ;g³;ø �BÖˆ€ €¿½=x€wˆà›ÖÍ2»‚Xßû@8Š`D&Âv?A–ÛF«U·Æ?/a¤^Ò~[,Ó`;úæõ´3âk ¬7ÿ Í}|7Û`»™ExvM{`ñÁÞù)ö°ú¼rÌ+j c ­™ÓÔöú›ÕS®¡G;×ùýkMœµûÚ%N®Õ|åI$8_–Ûrº<T›òª-j´6Æò²»XµÜ†7ü€ŸÍfs¾»ÉíwÁ`0øK�>`«êëéÎþÒÙQ½$Ë*'q„ñlE£ pqÿ=ÏâÎ ;ên½ýîsÊ%€°[Þ#Ï>È<}õòŽuåúšx;ÄIg& #*ÊÆ7–†Û=\83@êw¨­4_®Ê †ˆ õN€î÷VLY»]sC�زO(�ê!V—Î Ëß¢è± ÒlªMo…µQy¿µyç’F¸e³¸Þn_:w8káÀÈ)¨°buþ¦z-µßpëüÒ!†ÂûÜ:¿V:ã§¢ÿi2™¥|f�yÌf³ƒ �~FÿÜÿíª¤¹‡ßúöÀÍ™ç¦%g9Äžm¾L]·ºónË ñ±öÜÞ Ø~xœÚ»(ô³ÍŽ9Þ^7Í zÛh\O¯#ŒW³�� �IDATl`;Z+KCœÉ1¶J ÅWѬÈR_ÑåšØþúWFri àEð³³Ùl—ï^B@È+s�?6þ#€ßðõÅìÚ¸rr±Öúmp¶ýɬ•WpW›ÝÏ=_ÁZÅ#W^(ÝýB¢ŽÍî…ç}=®pGm‹\T÷+î:·E;P<næ÷¾wŸåk÷ Ó¡°ÚAÖÈ(UÅÅA½Àš"ÈúqA¼Ôuq´-€;o®j«s®­q _¯ÙU²¦«_ØHÁø…Ùlö/øn%�„ܦÓÙ.€· Û_+"ÿÐù'¨òáeÁ® ž¦Y™þ?þ£È ‰ Ò,Ç̓Y9Ë/>ì«jöê“?ïh3X´Âí6 º«¤ ë‚·zS µêW±¥Ì5¯«Þ¢7„‡l¨¨: �5A±cx~@Z[Ýõõst*iÕiÔ†M%°ð±e´mŠª¼kL‹q•0; ë·ŒúñÜÙJ�ƳÕúTÚš¡Q}»¦Õ¢u€€ÿ�àÓéì ß¡„€[ž˜À§üЙÑ×ø#òUÜáCÓ‹p‹³÷ ðyy*³úÔ2Íqý4€TÕ!�5b$‰Ý6Áù"…1n–ݵ<�Í©µ•¡ÐúÙj»`ΪâÎó£µjaF!ËrdÈú½Äßgk-žÛvx¨*"ï[Ûr6�î<·ãµXf9ö¦ó#uÎQÕšQRÑ¡˜½‡Ûµ±•BÚߊU…Ís[õ8S/–4M éb aín>©@§I‘@€]�ÿf:ý2ß„€×ˆƒñäO�üIñýþøÐ]V?|vgôoGÛ½§$Ň{šeHÓ ½$.g aÑZšeìB=µž[ …´f¯M³Ÿuq¾ÖJÝÁ‡Ä­öëBg¦ (ˆ —#жÈE Euósô5þõZ€f†vihýûòêª&N(³"F€í~ÕMw^I]¯�øy�_˜Ng–ï>rRá.�òºæMw_üg�þs9«Ï-¬µØêõGQ«ªÜyìƒa«4kY×FÆé=õüõÖ}E`ÞêÅ¥S_]`¸•úa¿_朓8Ú8Û^·P<§Âú®®Pî¹›ãvªÞ«ª¸|nÕzc#wn`ºL1]¬"#<v§œÙ¯¥ÎÖ*žß—•ú‘\:;,Ï4_eÏ5•Ð4î±Ê4LËZÑ]§~/‚Ë : ÀwŠˆ³NÖzö�pÙŒ\Y–C€ úý“Éü>¾sÈiÀpÈëœÀ­ávØîêq¬™]W;ºfçÒ(6ׯ,{ýü}}ðï üMa!R{¥/€QÍbȮׯ5ÿ‚úã‹s†6ºáï”[‹¼ø=ûb«êî³Vm%:VTµÆ»¶npiýrÕÕã‰X,W)«¼¸rQÅ Ÿ`¸•Ô¼� U‹$Šõ®;ÎâüÎ�¾[sùjršà�y]³ZeÏŠ`Àå—{Át:¯Íz#ìÐ× ÀqµfÙGþ}ÒÌ9ŠÖœ zšÈb©ænýQe‰o€4ܪ™YäïÂNMÙu–ɨ·\vc\ßj˜Äõ΋i¨µÐþW´±ŠÒn ªAGE-ÒˆL$�~ãÌp뇞|öêU¾[�!§ˆ«×÷æ÷\:ÿc�Þ…r· ÖgÎA *SÜh• Ì ˆtšÞ¯_ÖÎàßÕh¨–9èxžæ~Ys®u|ÝÎàzÀÆ¡aǾpy ž5èȺ4+õ‚sö“¡!sšg‡^kWœÙ6q¶ª¸t~ˆ</û-?àç�ùÕ‡†Î}äÔÂ�B�ÜséüoøM0Øê#2/îOê<ª° \>¿ƒU–µªÀm ¼q0ƒ‰ šis@±Ý‹Gâ}ë«#‹§mõkñùåóô’_÷g¿´•®/NóÌîu·¦îchnm`“ L3§PЩÖçï<ëjr[™[ŸîÏ—X¤) ¬5X«øŠ7\¬½.·4Rc6]”Ù†b²¨á;˜-Ê:ƒ(2.KÒ¡0š-™Wy°LóŽ% ñÙ–~l F°\å¸//.žßyG™ø£‡öß„�B^'<·{óoÞséüx›ŸªªJÑs¾ØNθ͆™p™Lî˜W…rõЭÚl©«åyŠuvã¢6DV-Ê×ו}hÁâßЄG‚ÍwÆmö²R3ø±y¬ÏW³øb©!ò ílü.¦ ¡´ú&hÃU01&° ¶­¼F‘©Hb÷»,Ó Í:[viìù^«,,óóãÉäÇoìù& �„¼ŽEÀ7Üséüwø¯�vDDoLf. U ½Øº¦T¦ºÆ¾ÎK¯b2¯; Ö+îQ×FæÜ‰mFµ/ÕÚÖÿ"ØÚîµvì[)ÏW™´kÎ ¦±Šï´…BŒAì+ò»†+Ž ¶|;æzfdͨ–ñ™‘8BÚÝòYÈ"Í`Dž�ð€|`<™ìó/ŸP�BðÜîÍ÷xï=—Îÿ*€¿-À@àÛòI±nÝtTQˆ•V¼vØåe^H¨ ¬ïÚ'º¦. iW¬õ";Q,+ÁPU`ƒwù*¬n*ґ¨×!TÏÛÎ`KúRõÚñ¿³´Å€tûï#ˆ#gê#çY/Ù“zGe•€Dp_fí/O'óò/ �BÖ xÃ¥óÿ2Íì?µª?dn²"ð~Š\¬ Z‰w‘1p΂U0[¬²ZØmšá¨ÖÍu"#ˆ½/@GH⸼?öYŠå*mÃçžÌ][ãÚ~w¨�™U¢àÒ˜×Cv£Wž †É iÌØ]­«#¨§Nrïh(¾ž $B³§A%ÄÎûš…ýñ«l!^@|П‡ÊGìN¦lÅK�!GàÊîÍ«�~*êõþU”$?*"À[DäŽ"º-W™ë£ª6·µ©n½C_£Ñ޶ƒ}×úym*ð7™#2‚ÁVyê¥ïuù4xV¦ÃƒÕûæTZZOŠÙr ßtx¶¯X¥y)@B¯¢ˆÑxQeŠßà ![Z)W» ƒ¤¢…oÑU12¦fÈädzüŸß>ùd™Œ˜ß2jÞµ?=`À'dÜ@È93E�z��¾ À7ªêWø‹ œo4 – *ÿ}õ©møúÝø&Ô µnl*gÀ"å½3ØÂW~é]e¥àSW¯ãÆÁÔ…_f‹Ô¹Üù·»ªm¸Ý…Þ1ÏŸ;‰#Ü}é,Šõ¿^–»ÀýÂ1VZ€,·øú¯üˆ�Ÿ{ü9_ÀW÷S?Nƒ~\/`ô®‹ªŠ4·µÕŽÈHQ ¨Ö*î8¿S8ŒUõíy–ÿ—~/¹öùGŸYò/•f�9V&“ÀÜß~ÛßJƒÁ[�|%€¯ðu�þ€/ ºò©”›ï*—»Mkòe c«{Ä™ãd6ÃñÄ/× «bKbÕÈF‚bº¼¾¬ß!ªFAQd`$°ÐõO?Øê!‰c<wm¹­w´ÖzwÁªy]«íˆ­“R ›¢—‚©ÿåƒÜgŒù#UýÈ>óþeB@ÈkÊl6{ Àc�Þˆ‚€ïä¬Í¿ÑGfS=i¸°á9Ó,ÇîͱŸ- æËUg±\9Ó>‚#`eÜÓ8Ö}f8À…!Œ¯9è<¾ö"Zk k·BÔŸúÆ;Ï!‰ãOŠàíÏœyïï|üO3�xá‹÷ ¡� äö�ï�ðŽáp°ç3ð—| €oÜ6�«À.žmoŒÁ3/ܬöã뚘zêgçGé€gŒàž‹gGî¾x³Å »{-ÐÄbƒ\¼~çc -âð9ˆþâ*ÍヌžzšI„P�rb™Ngc�¿ïo�€Ñhô5ªú=ªö¯ .‹H®Î  6FðÔÕ›¢‘ŽØ"s�hå0X7Ð)² Zkª¦Øë³óðXg¢s~gQáÜÎçv†xãÊǬҴånÜe/¬PUUé#(_cíî±*þD?rõÚÞý�pu—3}B(�9…L&“Ï�ø €Ÿ‘>€3�v�Œ�lè­ÒlñÖ/¿üáÇŸ½6ʲ½$FK¹Ó`¾tÆ<½Ø”.ƒE ï'. ÏW¹Û.7Ün•ª*î87ô¶¾=»‹ÜQäœ�U]žõÁ:ŠcÀ Z{"Ä‘èb•I/Žà–Dž0öÂæÍFä²µzÙ9 àQ�¿¢Š½p}Mwy•à.�BN�ßðç¿âæç»rÎˆÛ ýnÿüV¯Ú!М‘O)¬UÜunÛ¨+°Vq÷¥²å¯+þ“²½ñ`«».œ‡ Ó �l–CŒÁÓWw‘fÕn€ÁV¢�d•Ú÷âþÇþ:¯!Ì�B^¾V/cv–[dy=ïÚãjãÑU1ß…ÑözÕßèjh­ÂDΰ'jøõ‹¶z1T̸íŒ[½QT-&±ªïýÄý}7¯!�„W€ªuëóâRúúí–QÜÔfõÁÑÎyÀwm4 vKÆãj ¬‘âKØÀ‘PqQ6Ï•ÂÄHÁ}_x6]eÙOóªB@yÅ �m'jDd¶ÌZS÷,·˜Ì-z±)³¡ÁÎ|•"Ž ’(rûôkâ¢ÊÄQ„8Äq\¿ÝO0ØJücëÝüœ©|ü9‘‘G zòB@yE#לmŠ‚MU<Íýû«,w@9�<¿»ð¦Ëçj?€Ùb‰'®¼€³£!.œa÷æÆÓy¹îoÄ5ðùì£ÏއöÚÍÉŠW �BÈ+ä±gw3FÞ _á¯~†ßÿE\¿jµP4òIâ¡÷~œÄ­€“Ø-¬¼ÁèõªÙ¿óp.QÔ�¤ÞØ©í@ „P�B^!‘‘ÿè·»uw­*î:vÙ»jþ* àeÁÚÔxo¢û¯µŠÏñ*Œ¸¦=ý~PàŽsCÜua§lé[Çí(vBN†C@ȉ཭h/ÅÿÂ[õ3ñ[“8Úì�¨Õ±‹•ó0âšï¿ üzÓ¹D”�„P�Bމ®ïïú‘b¢Þв¶ûU`Cn¥éÝ <üô‹øâ•ëE罗ŲÑ!B@yeo×ß1²³Õǰ߃µŠÜZäÖBÅÀÂ@ÄÀHUAn¹­RóyžÃªë1P4R ÇÞ­^‚^WA\k-Vi†ƒé‹•3r7¿|�Å`«‡áv¯ìäG¹½a �!'‡O—“vÿ¯ˆÔfóQdÐO,Ó¹ukôÅý"‚EšBDG}ˆòܵêu‚Ààìh Vë{“ò˜¢Ú<]â`²ÀÅsœßÙ®•!Xîºã Œ¦ n� „€rl¤Y¾–ô ú½R ·ÍoÍõûæ÷¹UØ\‘Yo,•äÈó `•æ˜.ÒVýá|™AÜ!æ ÎÊ•û, „€òJYe¶_|mDpaà€Û{¹­µ#6Çß°  ÐÖ*Ò<G–ÛÚ6CUEd\ûÞÅ*«‰…Û˜°ð[D©â€ë¼j„P�B^9;ù|#Økã^m=Vƒþ�¡�Ès‹,ÏKËß–2ب$PÌü‹CŒ*ÎP�B@9ΈÀݹ%¿fP9Z«È¸‡_ý"@wx¹¡� „w_XUìMçˆÁp«ïM{ÜÏEI!Ž"¤i ë­­µôûÁä^0_­\Ÿª/tlûŽË,/E‚øéýl¹Â|•bgÐGÔņ[Ib´•­ „P�B^.ƒjî®Xå€7ûñn|ÒjøãD@s‹žU Q—¿ŒëhUSu�ôÿΖn»Ÿ�°A†Alo¹š„Uš@†¼\„P�BŽUM{ÌÙÑ6Fƒ--€¯^?@šçXÛ5(XPuÃÆõ`Y 0*;™H¹ô "¸¶?ˆlóŠB@9Œ‘a½ìOƒ^—>üâ;óѹ,Ò[ÿt \Gxÿ*uÞyfaˆÀªZƼb„P�BŽ»ÎŽ4œ³‡%{£AÎ aÕÖî¹çâYˆžya¯tí ö!Ðt±h †[ rë·þ³|UÅÍé|ÝKÍ�\å#„€r ¨Èuúæœ]Œ�yqO•®—#ÎìEÄÛþñgÒǵ“ b)�¡� „›ÐÇ ÀÅϵ#í/µ-‚›ÒþŠÉ"=4à¯9‡(ð©édrƒŒ �BÈ1æùƒ�|:0Æx“[˘F›Þbí¿H„µ�n£€¬­È­…øçê!ø{¼Z„P�Bމ§¯^{æM—/Z¬éâ© #Ÿ° PÁt±�Ð`Ï¿ϳZÀ—ÒæW!‹,ƒÞ7™LžâÕ"äö‡}; 9AˆÈÿí ü½$ÆV/ÁV/A¿— Ž â8BGˆbS‹ì"Ƶ�ñÁÕ‘Π…&ø9^%B˜ „3/îMÞ÷…ooÎøÇ³%ö§‹2§iæ¾Wúe ¯)8ï Å™A`<O«Ç…­‹þª""¿w0žÜË«D�!ä˜IâèZ$ IâZPÊ@E¿Ÿ@Ȳ ¥@€1Nä¹E3ÞÙ@ Ôæ5y°­02fàoñ B@¹¨Õï|þÆ ‰ÛúçC¼ˆ`´ÕÇ`+ ~'€ú�oÊÇ©ú¶Ák›ÿøÌ�ÜÀÃ[)²Ü~~"!ädÀ�BN"ò]nöî~¹fïÿ-âúºØ^ô¨–jí½pp7±; ?ïÛDdw8² !�„ãäÌhô¶ jw2],±»?Á*kOÆUƒ~à#`“^!‰]# « kí¡6ÁÁk:à=¼R„P�BŽ—·î 3ñÆâ3ZÌï[ꡘñ«*’È”½¤«ppCÀÿûÃáð«x©¹ýa �!'‡^=â6·ë…é|ªø:€ÊèæxUEnë­~™ðƒ¼\„0@9´9s·ÖßTa-œ—¿ª7úіךåXey•ân¹?Ö¡;àÆ©ÊÝ�„0@¹ižßûA¡EØŸÎa ·?é®ç«¼üÅg^y6ÀªêÅ¡Ìf3^$B(�!ÇA/ŽB�`ºH!â~¼0>ÍoË™¿­)€ª­ï­Ð&qd”W‹ �BÈ11Üîµ~ÖOb,V©UÜÝê9“ Ù"-ƒ¿›åK«M`Q!pQ[�¼¸?áÅ"„€òj nJßÙ�¨ þX³ r l¾Ô,Á-Ê*B(�!]¬ò ‰£.kD~k_ž+ -Ó_ˆ"‰`Õ- û ¬*fËôHA9B(�!¯Q@×Ùöjs†nK‰ Z?Æ%�ô%EuÀy?!�„[å_ÎA"Èr[ËÑ}g»·v‡À-a„×ú�rrè­Ÿ…k-K#(—®~þ޵5ÁãõeŠB3�„[ˆˆŒÁp«UÅ*Ë0]¤H3Ûž™KðµV"`<_AìlµµEd£íòÜb¾ÊŽV  ªÂJ@B(�!LJ�Ó÷‹…ªu@E6@‚àº;àa]ÿ^âü_"#)¯!�„cb¶ZM$ÈaܶV±LórÖïÿk3·ª7xµ¡� „×›52»>ÀV*@*PdÞÛköím3ýCz�¨jíÐ.!"PÅ‹¼Z„P�Bމí^ÿE�˜În ?(áMbƒ$‰°Js¬Ò¼ðëš ¾qOD0Y¬�¸]€`»—”²!·I!Í,–YœE×e®ójB@9>®Y7 oo½x€un�Î%0Ž"8�¬É HÓ)‘10=j†U&eðßÀs¼T„P�BŽ‰ÇŸ½úâÝÏ¿ìãUo¸ëœoÜÍl¶8ŽÚGyµ¹ý¡�!'<Œ®EüZ7_iq-½þ0F:o‘DÆøÓ53 ]O«]Bã~^)B(�!ÇŠ~  ¼õ>â…@þ¥&ü㛂Z7ªß'•à<¶&$ø¯” ªØô>ËëD�!äÉrý?y®°9fŠ4³Èr·p™æÈ­º†>kªùEÜL?Ï-òÜ=®æè3‘ÄÆ Š¢RT(Üõ·Rƒøc\_ÅÕk{»¼R„Üþб‹ÄÎpØÈ¢(ú+ȃu}iuT¸€-"°Vñe÷Ük]—Àð±Ög³•·äyî·÷¹âÁUž#óÝÝPðøîƒ·ðJrûÃ"@BNVz ÀE3qÞþü¥/a¿´Ûkå èzø ƒþ81þß¼î<Å–ÿ/×ÿ ¡� „7â¢ö�îPT¶ûªUÖ_Ê9¹4%@ýÛº¯>èOW ÷­²Róhªà3¼J„œ X@È b2™(€‡\σâö’…„od¡¾´Ï×ÔnÆ×DQTféõói^%B˜ „Ü>&"ÿè×Zñ¿@0/ê-„}`ß6Ðý+µY‚­±ãI\2€�B(�!·ˆ{»ãïšð¯‚8®Šý¬Uôûq-½_Tò7Ħç ïõrañâõýgxy9p €Æd29‚Ó^Ë)¸œáGÆàùëc<wý�‘qéþ²~Àgý>¶z½†h—†[x¯!�„[˃/ûH…sþ“Cvk§Ë_%/BO�Çÿàe!„€rKÑלxŽ’ Уd Ö¬î£Ê,V9Æó½8Æp«^#6Fäx]¡� „ÜB¬µµÖ¢¸5+óC›Þ"ˆ—3õ†ƒOå%à÷õ—®~î±*•°ÖŽw �I£—$ô{½œW†“‹� 9‘È}ò|<ÓÜÅæ^\½å\½9†Bq÷…3Pu. `woܲ�IAˆÄ`±Ê°JsŒ¶{jD~üÊ –×…f�!·2ü �,Ž|@¸R¬”~�V‘[ « kµÚظ¥™…µîÛU–c¾J¡ªà>^B˜ „Üz–�öl­‹÷áÔ]‚RýºG ÛðâþÔgÕo ìî8¼!ëp// !Ì�B^= Gy°•€ÒœØC*‡?A٠놠�rࣼ$„P�Bn1Óél à^bGOµÎhÝ­Ûüç°“âsOrýŸ �BÈ«…¾Ï—ñýbS@×ÿâöOiUׂ �BÈ«†¼ËåìÂjÝ ˆâª^#¸|–+²<ol¬4�Œl\ëo±7]ü¯!�„W‰étö< ÏáHË�Å‚ÿ!SûÀøHÄ=ø ¼„P�B^EøïÚžÈw›¾œõýæóÕì�f�漄P�B^Eø¸�Ðö–}Ô:õ¨ßôßH„+›“Z>£U·â �Œ`ß–¼„œ<è@ÈÉ�ϰ*Ä|™ ð…úbûßzÊ_­nHØšP z�`Å+A�!äÕå�Î`ûpµ å?¹ôqÔÎØ òkGZ ( Ì-ЃÙlÆ �!�„WÅ>€$�Ú+ï)Ûù6“ñå‚Eë_Y§''x¡� „¼Úˆº @ͽWÚA=x€ ½õÛà €imÐYQ>æÝ¼„œÐ!'›Ñhð¸µxs=n3~?Ó/R÷a€W4{Ô½?3é‡ÉtÆÏBN(Ü@ÈÉç3Ç=+híð[´vÃÿäÐrrá�!'Ÿˆà;{n¼G‚­‚ŽÈÜ1ÚFnË,k¥ sÕÿ6Í8ú„œP˜¾#䄳½=8 `o]¨ °þUçÜ[+ò³UOŸ(ŠpagPÒØð¦¼õÉç®=Í+@ÈÉ„K�„œpæóÙ¾v«¶½R»Õ½}¥ñ_×´`S3�)Î1äYŽ>!�„×>v¨™ßñ’=ùÜ.[�B@y-à£e»í°øíê Pü¨æïµý€«Í€ @û_vÏÅmŽ<!'r:À®ÌÒaù_ßêÌÛE�1Õ<Àª6윊ÂXƒâ'ªè8 6"„€òZk€#Ü©‡<:Ø [‹Ýƒ)zq„3ƒ-¿Q@qf´…­~’¨bôô »yB(�!·‡UÈK:—*`­6Ž’@ŸcM�!ä¶JȆ»,j{ƒõ~iè°Õqùâ™`+! ª@α&„€òÚGýC±E»_Ñ2È‹ÆHÍ.¸Ì#t×€4å°B@ymÙ?4ø«âòùQ« ƒ«7Ç0æÈK ׂxŸÃN�!äµDõi˜E;’®r߯ç#LùKK¸Ói-Ü7#�v?õà×8ð„P�B^KŒyÊ �uf€m¯wžÙˆ[0b“y…B+a ®€ˆcƒ$Ž‹ÍŎŸä rÂ?68„œ|¦Óé\Z^ê{ý¤œÑë†Íê+þBsà5΂àú~öÑ÷pÔ ¡� „Ü|¤ë‡ÁîÁ/ìkE~VwŸÛÁ]çF°*a•渶7Át¾,–~CM�!äöáƒi}9…7Ec ŽY½Ha ÜL ¸¬Àb•áê1Ƴ¥°ùM5!'Ö�rJÁ‡\ਕº¥¯ßöç‚}3 Ðh,‚í~ËSX�OWîü™Ïr´ ¡� „Ü&L&ÓG£aóëq^�¨+îƒ Ëónà€·{I)�*�‹ù2ý}Ž4!ŸP„‘��4IDAT�„Û/Bðæ®ê=ko¼ë�Á|‘¶º Üz¿Anm)â( Oóq1!�„Û ‹/*ôÍIÁ`¾Lk‰|UE¿WnëC¸S3R-¶ –zácdB(�!·‚GÈ·Þ}élųÜúŠÝƒ)ÔZÜyvX…õÀàMw_€µÀ•Ý=LXøØ•«s ¡� „Ü~<¿b_„í82e‹_kmÕ Ã106VêëqR~L<Çá%„€r;¢ú@W[ uv¿]¾�xŠL�!ävĘQ·ì…*D¦ öÖ(â8‚*f9¤£bО€…€SOr€ ¡� „܆L&“+;;# ÈïK×¶ÿu¶À"°VquÏuT�Ûó¸8�!§i¾À! ät!?6F`ŒÛÂGDª®"€1#ã›þÔnF|{ ï!ä³�"òG—f�!·)¹µðÅg¯}ƒxÓå è%‘ æ"˜Í–�=»€�H3Û¶pÏ…3Èr‹ëãY•8P}„£K3�„Û5 ú¡bfo­"/ªþEË¿ÈcÐK"ôâIÁˆAä3®{ ;n™fX®2$qÄ �!Ì�Bn_ ÷_ÎçK¬–Æm:ªþ‹ïµ˜å·NWl|áÚÍ«\B(�!·/)€k�.ºµ{¬ þm"Su QÄÞ0W<Àa%ätÁ%�BN€çÛ?öåÿŠ ;Ê‚¿¦0ø‡• �BÈmÌd:M\­‚>ÐëEèõb$IÜJó—±¾l!hüM*­ Ê&@„œ2¸@Èéäaù¶ã9Do쟅ˆ ö½~RÏ ¨³6¹EÑ,h•gPUl%®©*îsL a€rÛóI7»÷ýÐ5vÀÝgyŽÜZ$‘A™ù™ÁÖ‹RB˜ „Üæ$±ùTäy®PÆóEÇ£ƒ~€"Ë-rk«½.m𼸺B�!ävææþø¡ógwÊ÷þ—²M@)lÏ�¬ZïPTˆªêUcLÊQ%„€r2x À[�à†wô3Æ`}#€ND'~ú9Ëá$ätÁ�BN/÷ºÙáh;bÿz1 Už€[� ¡� „œ >Z‹äˆÑFá_æá\ÿÒÜ–·,Ï‘åù§8”„P�BN÷¹9¾†1¾ÓpI †ç!„œ.X@ÈéeÀT CkÝ6ÀÅ*keýÀͱÅV/lƒ(Dù‹×÷Y�H�!ä1ö·¡K|¤/´@–[Læ+ì zHbƒsgFEÁ?}ñú>G’S—�9¥¤i>QÕ‰–k�Åô¾ýØbY ‰ bçüçG8’„P�BN“Ù,·V¬UÑ#îü;wf„3;ÃÐ"ðŽ$!�„F™‡âÈ Ž‘‘µÖ¿Úø7à)Ž"!§ôóC@Èée»Ÿ|> ëãYÞzŒ¬•�Ê®‚„ �BÈI �æ{I�X¥9D¤üÀÁd�l÷¡ÖPV�B@9<Äwé'�Á*íȈàúþ "‚Ñ ‰ �ìq 9°€SÌ•o<á×ýËɾlx|Ñ4èÌ` ;Û}ìl÷•£H3�„ˆˆy4Ëó?£E 2«�Æ´QàŸ$eW@B3�„“Éo¸¸/X¬rÌWykÚ/"å-È(�º�B@9‰¤Yö~��r«È­vöè`îo„S—�9å,Sûku`€@ÛûýµJ��"#€bb­p a€rÙO& |\½ã¯1ÖÝD!�Œ Œÿ0P¸¾�»ÿqýăONÿÜ—]žr ¡� „œ\~£þ­`]y¿ˆ Ž"1"/üâ¯dÅ¡#ätÂ%�B^|¸ë‡ …0Òÿ?ä°B@9É(ƒhk¦¯n7 ,F¤¸Ö¿Å#äôÂ]¾„¼N¶ý_ªw¾Ö¿DÆ­ îíùù@3�„S ÷S�I—ì7D‘ Óÿ÷r¼9ݰ× ºÖ׿£ðû8^„P�BNEü—=ø5ÿòÔ}™@àc0B(�!§C�<�… ÊÄEýâK÷Ó¥T] !�„àw*E°¯õTgl*øÍ›ûãŒÓþ‘@y]°3½ÁZûl«@õ­DÆ$7÷ÇGŒf�!§€ñdrED~iÍÝ ¨XÅÏ0ø �!ä2? à[ŸÐ?œLfßÌ"äõAÄ! äõE¯×{€'à|@Þ�Á'|ïd2ûŽ!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„By=óÿ=L¡c¹����IEND®B`‚���������������������������������������������������������������������������quakespasm-0.91.0/Misc/fs_search_order.patch��������������������������������������������������������0000644�0000000�0000000�00000002203�12646150004�017510� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������allow plain files to override files inside a PAK file -- Sander van Dijk. Index: Quake/common.c =================================================================== --- Quake/common.c (revision 1280) +++ Quake/common.c (working copy) @@ -1911,13 +1911,6 @@ static void COM_AddGameDirectory (const else path_id = 1U; _add_path: - // add the directory to the search path - search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t)); - search->path_id = path_id; - q_strlcpy (search->filename, com_gamedir, sizeof(search->filename)); - search->next = com_searchpaths; - com_searchpaths = search; - // add any pak files in the format pak0.pak pak1.pak, ... for (i = 0; ; i++) { @@ -1949,6 +1942,13 @@ _add_path: if (!pak) break; } + // add the directory to the search path -- moved here from before the pakX.pak loop -- svdijk. + search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t)); + search->path_id = path_id; + q_strlcpy (search->filename, com_gamedir, sizeof(search->filename)); + search->next = com_searchpaths; + com_searchpaths = search; + if (!been_here && host_parms->userdir != host_parms->basedir) { been_here = true; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Misc/fitzquake080sdl.txt����������������������������������������������������������0000644�0000000�0000000�00000006763�11513277221�017060� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������================================================================================ Beta release of an SDL port of Fitzquake version 0.80, July 5, 2008 Author : Kristian Duske Email Address : deceive.inveigle.obfuscate@gmail.com Author's Homepage : http://www.kristianduske.com/fitzquake Minimum SDL version : 1.2.10 This is a port of the Fitzquake engine to SDL. The main goal of this port is to allow fitzquake to run on all major platforms. Currently there are builds for Windows, Linux and Mac OS X. To run this engine, you need to install the SDL and SDL_net library binaries. For Linux, you should probably use the packages for your distribution which should be available through your package manager of choice. The minimum SDL version you need to run this is 1.2.10. On Windows, you can download the SDL and SDL_net dlls from http://www.libsdl.org/. On Mac, the SDL framework is included in the application bundle. The Mac OS X version includes a simple launcher program. Known issues: - Mouse sensitivity is different than in the original Fitzquake (or vanilla Quake, for that matter). - Pasting from the clipboard does not work. - It is not possible to switch the screen refresh rates from within the engine. - On Linux, there are problems with the default sound sampling rate of 11025Hz. This can be fixed by supplying -sndspeed 48000 on the commandline. Changes since the March 7 beta: - discard mouse movement while input is deactivated - implement maps and mods commands using POSIX functions and added a POSIX wrapper for Win32 - activate mouse input when binding a key, otherwise mouse keys cannot be bound through the menu - fixed shift key behaviour - implemented TCP networking - fixed fog command (use fmax instead of max in Fog_FogCommand_f) - fixed bug that lead to the screen being set to minimum size when the sizedown command is issued multiple times - LSHIFT + ESC and circomflex always opens the console - print everything to stdout - and more... ChangeLog: ---------- 01/22/2008 - release mouse pointer when console is active. - enable key repeats (doesn't work on OS X, test in Win32).c 01/23/2008 - implement Sys_SendKeyEvents - disable mouse input when console is inactive using SDL_SetEventFilter - move mouse input processing to main event loop - add vid.mode to determine window mode - fixed Sys_printf() - enable key repeats when console is active only - return 0 if any of the cl_bob vars is 0 in V_CalcBob 01/24/2008 - changed in_deactivate so that it does not always release the mouse cursor - adapted all calls to in_activate and in_deactive, because they need to be called regardless of the current mode - added platform dependent messagebox code for fatal errors on OS X and Windows 02/06/2008 - fixed numlock acting as caps lock issue - fixed: input is not activated on map command (hopefull got them all this time) - center window in windowed modes 2008/03/14 - discard mouse movement while input is deactivated - implement maps and mods commands using POSIX functions and added a POSIX wrapper for Win32 - activate mouse input when binding a key, otherwise mouse keys cannot be bound through the menu - fixed shift key behaviour 2008/06/3 - fixed numerous bugs in sdl_net.c 2008/06/4 - fixed fog command (use fmax instead of max in Fog_FogCommand_f) - fixed bug that lead to the screen being set to minimum size when the sizedown command is issued multiple times 2008/07/4 - LSHIFT + ESC and circomflex always opens the console 2008/07/5 - print everything to stdout �������������quakespasm-0.91.0/Quakespasm.txt��������������������������������������������������������������������0000644�0000000�0000000�00000054660�12646136756�015357� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� QuakeSpasm ____________________________________________________________ Table of Contents 1. About 2. Downloads 3. Hints 3.1 Music Playback 4. Compiling and Installation 4.1 Linux/Unix 4.2 Windows 4.3 Mac OS X 5. Known Bugs 6. Changes 6.1 Changes in 0.91.1 6.1.1 Bugfixes 6.1.2 Visual improvements 6.1.3 Interface improvements 6.1.4 Code cleanup / Other 6.1.5 Raised limits 6.2 Changes in 0.90.1 6.2.1 Bugfixes 6.2.2 Performance 6.2.3 Visual improvements 6.2.4 Interface improvements 6.2.5 Code cleanup 6.3 Changes in 0.90.0 6.4 Changes in 0.85.9 6.5 Changes in 0.85.8 6.6 Changes in 0.85.7 6.7 Changes in 0.85.6 6.8 Changes in 0.85.5 6.9 Changes in 0.85.4 6.10 Changes in 0.85.3 6.11 Changes in 0.85.2 6.12 Changes in 0.85.1 7. Todo 8. Copyright 9. Contact 10. Links ______________________________________________________________________ Page last edited: December 2015 1. About QuakeSpasm <http://quakespasm.sourceforge.net> is a Quake 1 engine based on the SDL port of FitzQuake <http://www.celephais.net/fitzquake>. It includes support for 64 bit CPUs and custom music playback, and includes a new sound driver, some graphical niceities, and numerous bug-fixes and other improvements. 2. Downloads o Project Downloads: http://quakespasm.sourceforge.net/download.htm o Automatic Builds: http://quakespasm.ericwa.com/job/quakespasm-sdl2/ 3. Hints Visit the FitzQuake homepage <http://www.celephais.net/fitzquake> for a full run-down of the engine's commands and variables. o To disable some changes, use "quakespasm -fitz" o Quakespasm's custom data is stored in "quakespasm.pak". Install this file alongside your id1 directory to enable the custom console background and other minor features. o For different sound drivers use "SDL_AUDIODRIVER=DRIVER ./quakespasm" , where DRIVER may be alsa, dsp, pulse, esd ... o Shift+Escape draws the Console. o From the console, use UP to browse the command line history and TAB to autocomplete command and map names. o There is currently no CD Music volume support and SDL2 doesn't support CD audio. cd_sdl.c needs replacing with cd_linux.c, cd_bsd.c etc.. o In windows, alternative CD drives are accessible by "quakespasm -cddev F" (for example) o Quakespasm allows loading new games (mods) on the fly with "game GAMENAME {-quoth/hipnotic/rogue}" o Use "quakespasm -condebug" to save console log to "qconsole.log". SDL2 builds no longer generate stdout.txt/stderr.txt. 3.1. Music Playback Quakespasm can play various external music formats, including MP3, OGG and FLAC. o Tracks should be named like "track02.ogg", "track03.ogg" ... (there is no track01) and placed into "Quake/id1/music". o Unix users may need some extra libraries installed: "libmad" or "libmpg123" for MP3, and "libogg" and "libvorbis" for OGG. o As of 0.90.0, music is played back at 44100 Hz by default with no need to adjust "-sndspeed". o Use the "-noextmusic" option to disable this feature. o See Quakespasm-Music.txt for more details. 4. Compiling and Installation Quakespasm's (optional) custom data is now stored in the file quakespasm.pak. This file should be placed alongside your quakespasm binary and id1 directory. To check-out the latest version of QuakeSpasm, use svn co svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm 4.1. Linux/Unix After extracting the source tarball, browse the Makefile and edit the music streaming options, then ______________________________________________________________________ make cp quakespasm /usr/local/games/quake (for example) ______________________________________________________________________ Compile time options include o make DO_USERDIRS=1 to include user directories support o make DEBUG=1 for debugging o make SDL_CONFIG=/PATH/TO/SDL-CONFIG for unusual SDL installations o make USE_SDL2=1 to compile against SDL2 instead of SDL-1.2 Streaming music playback requires "libmad" or "libmpg123" for MP3, and "libogg" and "libvorbis" for OGG files. The project can also be built with Codeblocks (project files included). 4.2. Windows The QuakeSpasm developers cross-compile windows binaries using MinGW <http://www.mingw.org> and Mingw-w64 <http://mingw-w64.sf.net>. The project can also be built using Visual Studio 2005 (or newer). 4.3. Mac OS X A Quakespasm App (including program launcher and update framework) can be made using the Xcode template found in the MacOSX directory. Alternatively, have a look at Makefile.darwin for more instructions on building from a console. 5. Known Bugs Brightness issues should be fixed with GLSL gamma in 0.90.1, if your system supports OpenGL 2. For reference on older systems: Some versions of Xorg and SDL have brightness issues. Try setting "export SDL_VIDEO_X11_NODIRECTCOLOR=1", or if you have Xorg >= 7.5 and broken brightness, these patched libSDL binaries may help. o Gamma patched libSDL (i686-linux) http://sourceforge.net/projects/quakespasm/files/Support%20Files/libSDL_gamma_patched.tgz/download o Gamma patched libSDL (x86_64-linux) http://sourceforge.net/projects/quakespasm/files/Support%20Files/libSDL_gamma_patched-AMD64.tgz/download The "game" command doesn't execute quake.rc in the new game directory being switched to. This means any custom key bindings in a mod's config.cfg or special settings in a quake.rc won't be loaded. The only workaround is launching the engine with the -game command-line switch instead of using the game console command. Or, after running the game command, you can run "exec quake.rc" by yourself (YMMV). 6. Changes 6.1. Changes in 0.91.1 6.1.1. Bugfixes o Fix unwanted fog mode change upon video restart. o Work around Intel 855 bug in status bar drawing with "r_oldwater 0" and "scr_sbaralpha 0". o Fix an obscure GLSL bug where changing gamma would result in the screen turning to noise. o Fix GLSL gamma causing the tiled screen border to turn white when "sizedown" is used. o Fix an alias model VBO renderer bug where a model not precached during map start wouldn't be drawn. o Fix the order of OpenGL context creation and window creation in SDL2 video. o Fix a calling convention issue in windows DPI awareness function pointers. o Fix a random texture recoloring after video mode change. o Fix a liquid turning to garbage after several video mode changes and "r_oldwater 0". o Fix a wrong alpha-sorting bug introduced in 0.90.1. o Fix "flush" command not reloading mdl's from disk (bug introduced in 0.90.1). o Prevent a possible buffer overflow in Cbuf_Execute (old Q1/Q2 bug). o Prevent a possible vulnerability in MSG_ReadString (old Q1/Q2 bug). 6.1.2. Visual improvements o New cvars r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ/RMQEngine, non-archived, default to 0), and new worldspawn keys _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm, similar to the behaviour of the "fog" worldspawn key). o GLSL gamma is now supported on older hardware without NPOT extension. 6.1.3. Interface improvements o New r_pos command to show player position. o NaN detection in traceline with "developer 1" set now warns instead of errors. 6.1.4. Code cleanup / Other o Update third-party libraries. 6.1.5. Raised limits o Default max_edicts 8192 (was 2048) and no longer saved to config.cfg. o Default heapsize 256 MB (was 64 MB). o Default zone 4 MB (was 384 KB). o Raised MAX_SFX to 1024 (was 512). 6.2. Changes in 0.90.1 6.2.1. Bugfixes o Fix dynamic light artifact where changing lightmap are rendered one frame late (bug introduced in 0.90.0). o Fix texture memory leak when changing video modes with SDL2. o Fix rare incorrect mdl lighting on 64-bit builds. (details here: http://forums.insideqc.com/viewtopic.php?f=3&t=5620) o Fix fullbrights turning black after "kill" command (bug introduced in 0.90.0). o Clear all fog values on map change to prevent colored fog carrying over to jam3_tronyn.bsp. o Allow loading saves with } character in quoted strings, fixes issue with retrojam1_skacky.bsp. o Fix viewmodel not lerping on extended-limit maps. o Fix crash on out-of-bounds skin number. 6.2.2. Performance o Use multithreaded OpenGL on OS X for better performance. o New, faster mdl renderer using GLSL. Disable with "-noglslalias". 6.2.3. Visual improvements o New gamma correction implementation using GLSL. Fixes all known gamma issues (affecting the full display, persisting after quitting, or darkening the screen on OS X). Disable with "-noglslgamma". o Use high-quality water by default (r_oldwater 0). o Shadows use stencil buffer to avoid overlapping artifacts (from MarkV.) o r_noshadow_list cvar added (from MarkV.) 6.2.4. Interface improvements o Support pausing demo playback with the "pause" command. o Autocompletion for "game", "record", "playdemo". o Experimental windowed fullscreen mode available with vid_desktopfullscreen 1 (only in SDL2 builds, takes effect upon entering fullscreen mode the next time.) o Silence "exceeded standard limit" messages unless developer cvar is >= 1. o Some spam moved from developer 1 to 2: "can't find tga/lit/ent", "trying to load ent", "bad chunk length", "meshing", "PR_AlocStringSlots: realloc'ing" 6.2.5. Code cleanup o Clean up IDE project files to build on fresh systems. o Update 3rd-party libraries. 6.3. Changes in 0.90.0 o Fix issues on Windows systems with DPI scaling. o Unix/Mac user directories support. Disabled by default, 'make DO_USERDIRS=1' to enable it. o SDL2 support. Disabled by default, 'make USE_SDL2=1' to enable it. o Revised keyboard input code. o Revised/improved the 'game' command, i.e. on-the-fly mod changing. It now accepts an optional second argument for mission packs or quoth support i.e. -hipnotic, -rogue, or -quoth. For example, for WarpSpasm: "game warp -quoth" o Command line: "-game {quoth/hipnotic/rogue}" is now treated the same as -quoth, -hipnotic, or -rogue. o Console speed now resolution-independent. o Disabled gl_zfix, which caused glitches and is undesirable for new maps. Replacement .ent files to fix z-fighting for several id1 maps added to quakespasm.pak. o PF_VarString buffer bumped to 1024, avoids truncated centerprints from the 'In The Shadows' mod. o Support for opengl non-power-of-two-textures extension (disable with command line: "-notexturenpot".) o Support for OpenGL vertex buffer objects (VBO, OpenGL 1.5 or newer) for world and brush models (disable with command line: "-novbo".) o Antialiasing (FSAA) support (command line: -fsaa x, where x can be 0, 2, 4, 8). o Fence textures support. o Dynamic light speedup. Speedup loading of tga and pcx external images. o Brush model drawing speedup. o Support for BSP2 and 2PSB map formats. o Support for Opus, FLAC, and tracker music (S3M, IT, UMX, etc.), as compile-time options. o Music and sfx now mixed at 44100 Hz to avoid downsampling music. Low-pass filter applied to the sfx if -sndspeed is 11025 (the default), to preserve the same sound quality as 0.85.9. New -mixspeed option sets the rate for mixing sfx and music, and output to the OS (default 44100), setting it to 11025 reverts to 0.85.9 behaviour. New snd_filterquality cvar, value can be between 1 (emulate OS X resampler) and 5 (emulate Windows resampler), controls the sound of the low-pass filter. o Better Hor+ field of view (FOV) scaling behavior. o Better cross-map demo playback support. o Fix screenshots when screen width isn't a multiple of 4. o Fix a lighting glitch due to floating point precision. o Fix a looping sounds glitch. o Fix a vulnerability in file extension handling. Tighten path handling safety. o Initialize opengl with 24-bit depth buffer at 32 bpp. o Reset all models upon gamedir changes. (Fixes failures with mods using custom content.) o Fix broken behavior upon gamedir changes if -basedir is specified on the command line. o NET_MAXMESSAGE and MAX_MSGLEN limits bumped to 64000. o MAX_EFRAGS bumped to 4096, and MAX_CHANNELS to 1024. o MAX_ENT_LEAFS bumped from 16 to 32 to work around disappearing or flickering brush models in some situations. Also, if an entity is visible from MAX_ENT_LEAFS or more leafs, we now always send it to the client. o Fix cvar cycle command not working sometimes. o Host_Error upon missing models. (Prevents segmentation faults.) o Change sv_aim default value to 1 (i.e. turn off autoaim) o Add 'prev' and 'next' keywords to the 'cd' command. o Work around a linux cdrom issue (playback might not start for a while after a stop). o Quakespasm content customization moved from engine-embedded into a new optional quakespasm.pak file. o Version bumped to 0.90.0 (because Quakespasm has a decent life of it's own) o Other fixes and clean-ups. 6.4. Changes in 0.85.9 o Fixes for several undefined behaviors in C code (gcc-4.8 support.) o Implemented Hor+ style field of view (FOV) scaling, useful for widescreen resolutions. Configured by new cvar fov_adapt: set it to 1 and your fov will be scaled automatically according to the resolution. Enabled by default. o Adjusted string buffers for PR_ValueString and friends to fix crashes with excessively long global strings seen in some rude mods. o Toned down warning messages from PF_VarString() a bit. o Fixed Fitzquake's map existence check in changelevel (used to leak file handles which would end up in a Sys_Error() due to consuming all free handles if many maps reside not in pak files.) o Fixes/cleanups in chat mode handling. Client no longer gets stuck in chat mode upon disconnect. o Mouse grab/key_dest fixes and key cleanups. o The "speedkey" now acts as "slowkey" when "always run" is on. o Support for demo recording after connection to server. (thanks to Baker for a patch) o Corner case fixes in COM_Parse() for quoted strings and support for C-style /*..*/ comments. o Changed lightmaps to GL_RGBA instead of GL_RGB. o Better parse for opengl extensions list (from quakeforge.) o Vsync saving/loading fixes. o Fixed pointfile loading. o Multiple cleanups in gl_vidsdl.c. o Opus music decoding support (as an optional patch only.) o Several other minor fixes/cleanups. 6.5. Changes in 0.85.8 o Made Quake shareware 1.00 and 1.01 versions to be recognized properly. o Fixed control-character handling in unicode mode. Keyboard input tweaks. o Made the keypad keys to send separate key events in game mode. o Text pasting support from OS clipboard to console. (windows and macosx.) o Support for the Apple (Command) key on macosx. o Fixed increased (more than 32) dynamic lights. o Music playback: Made sure that the file's channels count is supported. o Support for Solaris. o Switched to using libmad instead of libmpg123 for MP3 playback on Mac OS X. o Better support for building the Mac OS X version using a makefile, support for cross-compiling on Linux. o Fixed a minor intermissions glitch. o Increased string buffer size from 256 to 384 for PF_VarString to work around broken mods such as UQC. o Restored original behavior for Quake registered version detection. o Minor demo recording/playback tweaks. o Minor tweaks to the scale menu option. o unbindall before loading stored bindings (configurable by new cvar cfg_unbindall, enabled by default.) o New icon. o Miscellaneous source code cleanups. 6.6. Changes in 0.85.7 o Added support for cross-level demo playback o gl_texturemode is reimplemented as a cvar with a callback and the setting is automatically saved to the config o Fixed execution of external files without a newline at the end o Reduced memory usage during reloading of textures o Fixed compilation on GNU/kFreeBSD (Debian bug #657793) o Fixed backspace key on Mac OS X o Disable mouse acceleration in Mac OS X o Worked around recursive calling of the anisotropic filter callback o Console word wrap and long input line fixes o Verified correct compilation by clang (using v3.0) o Several other small changes mostly invisible to the end-user 6.7. Changes in 0.85.6 o More work for string buffer safety o Reverted v0.85.5 change of not allowing deathmatch and coop cvars to be set at the same time (was reported for possibility of causing compatibility issues with mods) o Several cleanups/changes in the cvar layer o Minor SDL video fixes. 6.8. Changes in 0.85.5 o SDL input driver updated adding native keymap and dead key support to the console o Fixed a crash in net play in maps with extended limits o Verified successful compilation using gcc-4.6.x o Added workaround against GL texture flicker (z fighting), controlled by new cvar 'gl_zfix' o Read video variables early so that a vid_restart isn't necessary after init o mlook and lookspring fixes o Added support for loading external entity files, controlled by new cvar 'external_ents' o Made mp3 playback to allocate system memory instead of zone o Some updates to the progs interpreter code o Fixed r_nolerp_list parsing code of fitzquake o Made sure that deathmatch and coop are not set at the same time o Several code updates from uHexen2 project, several code cleanups. 6.9. Changes in 0.85.4 o Implement music (OGG, MP3, WAV) playback o A better fix for the infamous SV_TouchLinks problem, no more hard lockups with maps such as "whiteroom" o Add support for mouse buttons 4 and 5 o Fix the "unalias" console command o Restore the "screen size" menu item o Fixed an erroneous protocol check in the server code o Raised the default zone memory size to 384 kb o Raised the default max_edicts from 1024 to 2048 o Revised lit file loading, the lit file must be from the same game directory as the map itself or from a searchpath with a higher priority o Fixed rest of the compiler warnings o Other minor sound and cdaudio updates 6.10. Changes in 0.85.3 o Fix the "-dedicated" option (thanks Oz) and add platform specific networking code (default) rather than SDL_net o Much needed OSX framework stuff from Kristian o Add a persistent history feature (thanks Baker) o Add a slider for scr_sbaralpha, which now defaults to 0.95 (slightly transparent, allowing for a nicer status bar) o Allow player messages longer than 32 characters o Sockaddr fix for FreeBSD/OSX/etc networking o Connect status bar size to the scale slider o Include an ISNAN (is not-a-number) fix to catch the occassional quake C bug giving traceline problems o Enumerate options menus o Add a "prev weapon" menu item (from Sander) o Small fix to Sound Block/Unblock on win32 o Lots of code fixes (some from uhexen2) o Sys_Error calls Host_Shutdown o Added MS Visual Studio support o Add a "-cd" option to let the CD Player work in dedicated mode, and some other CD tweaks. 6.11. Changes in 0.85.2 o Replace the old "Screen size" slider with a "Scale" slider o Don't constantly open and close condebug log o Heap of C clean-ups o Fix mapname sorting o Alias the "mods" command to "games" o Block/Unblock sound upon focus loss/gain o NAT fix (networking protocol fix) o SDLNet_ResolveHost bug-fix allowing connection to ports other than 26000 o Bumped array size of sv_main.c::localmodels from 5 to 6 fixing an old fitzquake-0.85 bug which used to cause segfaults depending on the compiler. o Accept commandline options like "+connect ip:port" o Add OSX Makefile (tested?) 6.12. Changes in 0.85.1 o 64 bit CPU support o Restructured SDL sound driver o Custom conback o Tweaked the command line completion and added a map/changelevel autocompletion function o Alt+Enter toggles fullscreen o Disable Draw_BeginDisc which causes core dumps when called excessively o Show helpful info on start-up o Include real map name (sv.name) and skill in the status bar o Remove confirm quit dialog o Don't spam the console with PackFile seek requests o Default to window mode o Withdraw console when playing demos o Don't play demos on program init o Default Heapsize is 64meg o Changes to default console alpha, speed o Changes to cvar persistence gl_flashblend (default 0), r_shadow, r_wateralpha, r_dynamic, r_novis 7. Todo o Add uHexen2's first person camera (and menu item) o Native CD audio support (if desired). cd_sdl.c doesn't have proper volume controls and SDL2 doesn't support CD audio 8. Copyright o Quake and Quakespasm are released under the GNU GENERAL PUBLIC LICENSE Version 2: http://www.gnu.org/licenses/gpl-2.0.html o Quakespasm console background image by AAS, released under the CREATIVE COMMONS PUBLIC LICENSE: http://creativecommons.org/licenses/by/3.0/legalcode 9. Contact o QuakeSpasm Project page: http://sourceforge.net/projects/quakespasm o Bug reports: http://sourceforge.net/p/quakespasm/bugs/?source=navbar o Ozkan <mailto:gmail - dot - com - username - sezeroz> (project leader), Eric <mailto:gmail - dot - com - username - ewasylishen>, Sander <mailto:gmail - dot - com - username - a.h.vandijk>, Stevenaaus <mailto:yahoo - dot - com - username - stevenaaus> 10. Links o QuakeSpasm Homepage: http://quakespasm.sourceforge.net o Downloads: http://quakespasm.sourceforge.net/download.htm o FitzQuake Homepage: http://www.celephais.net/fitzquake o Func Quakespasm forum: http://www.celephais.net/board/view_thread.php?id=60452 o Inside3D forums: http://forums.insideqc.com ��������������������������������������������������������������������������������quakespasm-0.91.0/Quakespasm-Music.txt��������������������������������������������������������������0000644�0000000�0000000�00000006346�12405526374�016423� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������QuakeSpasm supports ogg, mp3 and wav external music files to be played instead of cd music. What you should do is simple: 1. Use your favorite cd-ripper application and rip your quake cdrom audio tracks, convert them to ogg or mp3 so they occupy less space, like track02.ogg, track03.ogg, etc. Note #1: There is no such thing as track01: the first tracks of original Quake and the mission pack cdroms are always data tracks. Note #2: Since the Quake cdrom audio tracks are pre-emphasized, you should de-emphasize them during or after ripping to make them sound right. (thanks to Sander van Dijk for this note) 2. Go into your quake installation directory and create a new directory id1/music (for windows users id1\music). 3. If you have the Scourge of Armagon mission pack, then create another directory hipnotic/music . If you have the Dissolution of Eternity then create another directory rogue/music . 4. Take the ripped music files from step1, place them under id1/music. If you have the mission packs, repeat step1 for the mission packs, too, and place the ripped music files under hipnotic/music for the first mission pack or under rogue/music for the second mission pack. 5. All are ready to go: When a level starts, the engine will first try playing the necessary cdaudio track and if it doesn't find the cdrom it will use the ripped music files instead. New console commands: --------------------- - music <filename> Start playing the requested music file. Example: music mymusic1 Notice that you don't have to type the file extension: The requested music will be searched with ogg, mp3, and then with a wav extension, automatically. If you do specify the file extension, like "music mymusic1.wav", then it will honor your wish and try only the given type: this is good for testing/comparing the same music in different formats. - music_stop Stops the playing music - music_pause Pauses the playing music - music_resume Resumes playing the music if it was paused - music_loop 1 Makes the background music to loop (default behavior) - music_loop 0 Makes the background music to play once and then stop New cvars: ------------------------- - bgm_extmusic (0 or 1): Disable or enable playback of external music files instead of cdaudio. default is 1 (enabled). New command line options: ------------------------- - -noextmusic: Disables the playback of external music files instead of cdaudio. Music files in PAK files: ------------------------- PAK-contained music files are fully supported. Music file directories: ------------------------- - The music files are always searched under the "music" subdirectory of a game. Music file search order: ------------------------- The engine can handle multiple audio formats. The map-dictated music, i.e. the ripped cd music, is always searched by the order of searchpath priority: the file from the searchpath with the highest priority is chosen, because it is most likely the one from our own game directory itself. This way, if a mod has track02 as a mp3 or wav, which is below track02.ogg in the music_handler order, the mp3 or wav will still have priority over track02.ogg from the id1 game directory. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/����������������������������������������������������������������������������0000755�0000000�0000000�00000000000�12646150016�013520� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_umx.c�������������������������������������������������������������������0000644�0000000�0000000�00000024430�12276500543�015347� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Unreal UMX container support. * UPKG parsing partially based on Unreal Media Ripper (UMR) v0.3 * by Andy Ward <wardwh@swbell.net>, with additional updates * by O. Sezer - see git repo at https://github.com/sezero/umr/ * * The cheaper way, i.e. linear search of music object like libxmp * and libmodplug does, is possible. With this however we're using * the embedded offset, size and object type directly from the umx * file, and I feel safer with it. * * Copyright (C) 2013 O. Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #include "quakedef.h" #if defined(USE_CODEC_UMX) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_umx.h" typedef int32_t fci_t; /* FCompactIndex */ #define UPKG_HDR_TAG 0x9e2a83c1 struct _genhist { /* for upkg versions >= 68 */ int32_t export_count; int32_t name_count; }; struct upkg_hdr { uint32_t tag; /* UPKG_HDR_TAG */ int32_t file_version; uint32_t pkg_flags; int32_t name_count; /* number of names in name table (>= 0) */ int32_t name_offset; /* offset to name table (>= 0) */ int32_t export_count; /* num. exports in export table (>= 0) */ int32_t export_offset; /* offset to export table (>= 0) */ int32_t import_count; /* num. imports in export table (>= 0) */ int32_t import_offset; /* offset to import table (>= 0) */ /* number of GUIDs in heritage table (>= 1) and table's offset: * only with versions < 68. */ int32_t heritage_count; int32_t heritage_offset; /* with versions >= 68: a GUID, a dword for generation count * and export_count and name_count dwords for each generation: */ uint32_t guid[4]; int32_t generation_count; #define UPKG_HDR_SIZE 64 /* 64 bytes up until here */ /*struct _genhist *gen;*/ }; /*COMPILE_TIME_ASSERT(upkg_hdr, offsetof(struct upkg_hdr, gen) == UPKG_HDR_SIZE);*/ COMPILE_TIME_ASSERT(upkg_hdr, sizeof(struct upkg_hdr) == UPKG_HDR_SIZE); #define UMUSIC_IT 0 #define UMUSIC_S3M 1 #define UMUSIC_XM 2 #define UMUSIC_MOD 3 #define UMUSIC_WAV 4 #define UMUSIC_MP2 5 static const char *mustype[] = { "IT", "S3M", "XM", "MOD", "WAV", "MP2", NULL }; /* decode an FCompactIndex. * original documentation by Tim Sweeney was at * http://unreal.epicgames.com/Packages.htm * also see Unreal Wiki: * http://wiki.beyondunreal.com/Legacy:Package_File_Format/Data_Details */ static fci_t get_fci (const char *in, int *pos) { int32_t a; int size; size = 1; a = in[0] & 0x3f; if (in[0] & 0x40) { size++; a |= (in[1] & 0x7f) << 6; if (in[1] & 0x80) { size++; a |= (in[2] & 0x7f) << 13; if (in[2] & 0x80) { size++; a |= (in[3] & 0x7f) << 20; if (in[3] & 0x80) { size++; a |= (in[4] & 0x3f) << 27; } } } } if (in[0] & 0x80) a = -a; *pos += size; return a; } static int get_objtype (fshandle_t *f, int32_t ofs, int type) { char sig[16]; _retry: FS_fseek(f, ofs, SEEK_SET); FS_fread(sig, 16, 1, f); if (type == UMUSIC_IT) { if (memcmp(sig, "IMPM", 4) == 0) return UMUSIC_IT; return -1; } if (type == UMUSIC_XM) { if (memcmp(sig, "Extended Module:", 16) != 0) return -1; FS_fread(sig, 16, 1, f); if (sig[0] != ' ') return -1; FS_fread(sig, 16, 1, f); if (sig[5] != 0x1a) return -1; return UMUSIC_XM; } if (type == UMUSIC_MP2) { unsigned char *p = (unsigned char *)sig; uint16_t u = ((p[0] << 8) | p[1]) & 0xFFFE; if (u == 0xFFFC || u == 0xFFF4) return UMUSIC_MP2; return -1; } if (type == UMUSIC_WAV) { if (memcmp(sig, "RIFF", 4) == 0 && memcmp(&sig[8], "WAVE", 4) == 0) return UMUSIC_WAV; return -1; } FS_fseek(f, ofs + 44, SEEK_SET); FS_fread(sig, 4, 1, f); if (type == UMUSIC_S3M) { if (memcmp(sig, "SCRM", 4) == 0) return UMUSIC_S3M; /*return -1;*/ /* SpaceMarines.umx and Starseek.umx from Return to NaPali * report as "s3m" whereas the actual music format is "it" */ type = UMUSIC_IT; goto _retry; } FS_fseek(f, ofs + 1080, SEEK_SET); FS_fread(sig, 4, 1, f); if (type == UMUSIC_MOD) { if (memcmp(sig, "M.K.", 4) == 0 || memcmp(sig, "M!K!", 4) == 0) return UMUSIC_MOD; return -1; } return -1; } static int read_export (fshandle_t *f, const struct upkg_hdr *hdr, int32_t *ofs, int32_t *objsize) { char buf[40]; int idx = 0, t; FS_fseek(f, *ofs, SEEK_SET); if (FS_fread(buf, 4, 10, f) < 10) return -1; if (hdr->file_version < 40) idx += 8; /* 00 00 00 00 00 00 00 00 */ if (hdr->file_version < 60) idx += 16; /* 81 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00 */ get_fci(&buf[idx], &idx); /* skip junk */ t = get_fci(&buf[idx], &idx); /* type_name */ if (hdr->file_version > 61) idx += 4; /* skip export size */ *objsize = get_fci(&buf[idx], &idx); *ofs += idx; /* offset for real data */ return t; /* return type_name index */ } static int read_typname(fshandle_t *f, const struct upkg_hdr *hdr, int idx, char *out) { int i, s; long l; char buf[64]; if (idx >= hdr->name_count) return -1; buf[63] = '\0'; for (i = 0, l = 0; i <= idx; i++) { FS_fseek(f, hdr->name_offset + l, SEEK_SET); FS_fread(buf, 1, 63, f); if (hdr->file_version >= 64) { s = *(signed char *)buf; /* numchars *including* terminator */ if (s <= 0 || s > 64) return -1; l += s + 5; /* 1 for buf[0], 4 for int32_t name_flags */ } else { l += (long)strlen(buf); l += 5; /* 1 for terminator, 4 for int32_t name_flags */ } } strcpy(out, (hdr->file_version >= 64)? &buf[1] : buf); return 0; } static int probe_umx (fshandle_t *f, const struct upkg_hdr *hdr, int32_t *ofs, int32_t *objsize) { int i, idx, t; int32_t s, pos; long fsiz; char buf[64]; idx = 0; fsiz = FS_filelength (f); /* Find the offset and size of the first IT, S3M or XM * by parsing the exports table. The umx files should * have only one export. Kran32.umx from Unreal has two, * but both pointing to the same music. */ if (hdr->export_offset >= fsiz) return -1; memset(buf, 0, 64); FS_fseek(f, hdr->export_offset, SEEK_SET); FS_fread(buf, 1, 64, f); get_fci(&buf[idx], &idx); /* skip class_index */ get_fci(&buf[idx], &idx); /* skip super_index */ if (hdr->file_version >= 60) idx += 4; /* skip int32 package_index */ get_fci(&buf[idx], &idx); /* skip object_name */ idx += 4; /* skip int32 object_flags */ s = get_fci(&buf[idx], &idx); /* get serial_size */ if (s <= 0) return -1; pos = get_fci(&buf[idx],&idx); /* get serial_offset */ if (pos < 0 || pos > fsiz - 40) return -1; if ((t = read_export(f, hdr, &pos, &s)) < 0) return -1; if (s <= 0 || s > fsiz - pos) return -1; if (read_typname(f, hdr, t, buf) < 0) return -1; for (i = 0; mustype[i] != NULL; i++) { if (!q_strcasecmp(buf, mustype[i])) { t = i; break; } } if (mustype[i] == NULL) return -1; if ((t = get_objtype(f, pos, t)) < 0) return -1; *ofs = pos; *objsize = s; return t; } static int32_t probe_header (void *header) { struct upkg_hdr *hdr; unsigned char *p; uint32_t *swp; int i; /* byte swap the header - all members are 32 bit LE values */ p = (unsigned char *) header; swp = (uint32_t *) header; for (i = 0; i < UPKG_HDR_SIZE/4; i++, p += 4) { swp[i] = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); } hdr = (struct upkg_hdr *) header; if (hdr->tag != UPKG_HDR_TAG) { Con_DPrintf("Unknown header tag 0x%x\n", hdr->tag); return -1; } if (hdr->name_count < 0 || hdr->name_offset < 0 || hdr->export_count < 0 || hdr->export_offset < 0 || hdr->import_count < 0 || hdr->import_offset < 0 ) { Con_DPrintf("Negative values in header\n"); return -1; } switch (hdr->file_version) { case 35: case 37: /* Unreal beta - */ case 40: case 41: /* 1998 */ case 61:/* Unreal */ case 62:/* Unreal Tournament */ case 63:/* Return to NaPali */ case 64:/* Unreal Tournament */ case 66:/* Unreal Tournament */ case 68:/* Unreal Tournament */ case 69:/* Tactical Ops */ case 75:/* Harry Potter and the Philosopher's Stone */ case 76: /* mpeg layer II data */ case 83:/* Mobile Forces */ return 0; } Con_DPrintf("Unknown upkg version %d\n", hdr->file_version); return -1; } static int process_upkg (fshandle_t *f, int32_t *ofs, int32_t *objsize) { char header[UPKG_HDR_SIZE]; if (FS_fread(header, 1, UPKG_HDR_SIZE, f) < UPKG_HDR_SIZE) return -1; if (probe_header(header) < 0) return -1; return probe_umx(f, (struct upkg_hdr *)header, ofs, objsize); } static qboolean S_UMX_CodecInitialize (void) { return true; } static void S_UMX_CodecShutdown (void) { } static qboolean S_UMX_CodecOpenStream (snd_stream_t *stream) { int type; int32_t ofs = 0, size = 0; type = process_upkg(&stream->fh, &ofs, &size); if (type < 0) { Con_DPrintf("%s: unrecognized umx\n", stream->name); return false; } Con_DPrintf("%s: %s data @ 0x%x, %d bytes\n", stream->name, mustype[type], ofs, size); /* hack the fshandle_t start pos and length members so * that only the relevant data is accessed from now on */ stream->fh.start += ofs; stream->fh.length = size; FS_fseek(&stream->fh, 0, SEEK_SET); switch (type) { case UMUSIC_IT: case UMUSIC_S3M: case UMUSIC_XM: case UMUSIC_MOD: return S_CodecForwardStream(stream, CODECTYPE_MOD); case UMUSIC_WAV: return S_CodecForwardStream(stream, CODECTYPE_WAV); case UMUSIC_MP2: return S_CodecForwardStream(stream, CODECTYPE_MP3); } return false; } static int S_UMX_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) { return -1; } static void S_UMX_CodecCloseStream (snd_stream_t *stream) { S_CodecUtilClose(&stream); } static int S_UMX_CodecRewindStream (snd_stream_t *stream) { return -1; } snd_codec_t umx_codec = { CODECTYPE_UMX, true, /* always available. */ "umx", S_UMX_CodecInitialize, S_UMX_CodecShutdown, S_UMX_CodecOpenStream, S_UMX_CodecReadStream, S_UMX_CodecRewindStream, S_UMX_CodecCloseStream, NULL }; #endif /* USE_CODEC_UMX */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_udp.c�������������������������������������������������������������������0000644�0000000�0000000�00000026446�12407762022�015337� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "q_stdinc.h" #include "arch_def.h" #include "net_sys.h" #include "quakedef.h" #include "net_defs.h" static sys_socket_t net_acceptsocket = INVALID_SOCKET; // socket for fielding new connections static sys_socket_t net_controlsocket; static sys_socket_t net_broadcastsocket = 0; static struct sockaddr_in broadcastaddr; static in_addr_t myAddr; #include "net_udp.h" //============================================================================= sys_socket_t UDP_Init (void) { int err; char *colon; char buff[MAXHOSTNAMELEN]; struct hostent *local; struct qsockaddr addr; if (COM_CheckParm ("-noudp")) return INVALID_SOCKET; // determine my name & address myAddr = htonl(INADDR_LOOPBACK); if (gethostname(buff, MAXHOSTNAMELEN) != 0) { err = SOCKETERRNO; Con_SafePrintf("UDP_Init: gethostname failed (%s)\n", socketerror(err)); } else { buff[MAXHOSTNAMELEN - 1] = 0; local = gethostbyname(buff); if (local == NULL) { Con_SafePrintf("UDP_Init: gethostbyname failed (%s)\n", hstrerror(h_errno)); } else if (local->h_addrtype != AF_INET) { Con_SafePrintf("UDP_Init: address from gethostbyname not IPv4\n"); } else { myAddr = *(in_addr_t *)local->h_addr_list[0]; } } if ((net_controlsocket = UDP_OpenSocket(0)) == INVALID_SOCKET) { Con_SafePrintf("UDP_Init: Unable to open control socket, UDP disabled\n"); return INVALID_SOCKET; } broadcastaddr.sin_family = AF_INET; broadcastaddr.sin_addr.s_addr = INADDR_BROADCAST; broadcastaddr.sin_port = htons((unsigned short)net_hostport); UDP_GetSocketAddr (net_controlsocket, &addr); strcpy(my_tcpip_address, UDP_AddrToString (&addr)); colon = strrchr (my_tcpip_address, ':'); if (colon) *colon = 0; Con_SafePrintf("UDP Initialized\n"); tcpipAvailable = true; return net_controlsocket; } //============================================================================= void UDP_Shutdown (void) { UDP_Listen (false); UDP_CloseSocket (net_controlsocket); } //============================================================================= void UDP_Listen (qboolean state) { // enable listening if (state) { if (net_acceptsocket != INVALID_SOCKET) return; if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == INVALID_SOCKET) Sys_Error ("UDP_Listen: Unable to open accept socket"); return; } // disable listening if (net_acceptsocket == INVALID_SOCKET) return; UDP_CloseSocket (net_acceptsocket); net_acceptsocket = INVALID_SOCKET; } //============================================================================= sys_socket_t UDP_OpenSocket (int port) { sys_socket_t newsocket; struct sockaddr_in address; int _true = 1; int err; if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { err = SOCKETERRNO; Con_SafePrintf("UDP_OpenSocket: %s\n", socketerror(err)); return INVALID_SOCKET; } if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR) goto ErrorReturn; memset(&address, 0, sizeof(struct sockaddr_in)); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons((unsigned short)port); if (bind (newsocket, (struct sockaddr *)&address, sizeof(address)) == 0) return newsocket; ErrorReturn: err = SOCKETERRNO; Con_SafePrintf("UDP_OpenSocket: %s\n", socketerror(err)); UDP_CloseSocket (newsocket); return INVALID_SOCKET; } //============================================================================= int UDP_CloseSocket (sys_socket_t socketid) { if (socketid == net_broadcastsocket) net_broadcastsocket = 0; return closesocket (socketid); } //============================================================================= /* ============ PartialIPAddress this lets you type only as much of the net address as required, using the local network components to fill in the rest ============ */ static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr) { char buff[256]; char *b; int addr, mask, num, port, run; buff[0] = '.'; b = buff; strcpy(buff+1, in); if (buff[1] == '.') b++; addr = 0; mask = -1; while (*b == '.') { b++; num = 0; run = 0; while (!( *b < '0' || *b > '9')) { num = num*10 + *b++ - '0'; if (++run > 3) return -1; } if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0) return -1; if (num < 0 || num > 255) return -1; mask <<= 8; addr = (addr<<8) + num; } if (*b++ == ':') port = atoi(b); else port = net_hostport; hostaddr->qsa_family = AF_INET; ((struct sockaddr_in *)hostaddr)->sin_port = htons((unsigned short)port); ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); return 0; } //============================================================================= int UDP_Connect (sys_socket_t socketid, struct qsockaddr *addr) { return 0; } //============================================================================= sys_socket_t UDP_CheckNewConnections (void) { int available; struct sockaddr_in from; socklen_t fromlen; char buff[1]; if (net_acceptsocket == INVALID_SOCKET) return INVALID_SOCKET; if (ioctl (net_acceptsocket, FIONREAD, &available) == -1) { int err = SOCKETERRNO; Sys_Error ("UDP: ioctlsocket (FIONREAD) failed (%s)", socketerror(err)); } if (available) return net_acceptsocket; // quietly absorb empty packets recvfrom (net_acceptsocket, buff, 0, 0, (struct sockaddr *) &from, &fromlen); return INVALID_SOCKET; } //============================================================================= int UDP_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr) { socklen_t addrlen = sizeof(struct qsockaddr); int ret; ret = recvfrom (socketid, buf, len, 0, (struct sockaddr *)addr, &addrlen); if (ret == SOCKET_ERROR) { int err = SOCKETERRNO; if (err == NET_EWOULDBLOCK || err == NET_ECONNREFUSED) return 0; Con_SafePrintf ("UDP_Read, recvfrom: %s\n", socketerror(err)); } return ret; } //============================================================================= static int UDP_MakeSocketBroadcastCapable (sys_socket_t socketid) { int i = 1; // make this socket broadcast capable if (setsockopt(socketid, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == SOCKET_ERROR) { int err = SOCKETERRNO; Con_SafePrintf ("UDP, setsockopt: %s\n", socketerror(err)); return -1; } net_broadcastsocket = socketid; return 0; } //============================================================================= int UDP_Broadcast (sys_socket_t socketid, byte *buf, int len) { int ret; if (socketid != net_broadcastsocket) { if (net_broadcastsocket != 0) Sys_Error("Attempted to use multiple broadcasts sockets"); ret = UDP_MakeSocketBroadcastCapable (socketid); if (ret == -1) { Con_Printf("Unable to make socket broadcast capable\n"); return ret; } } return UDP_Write (socketid, buf, len, (struct qsockaddr *)&broadcastaddr); } //============================================================================= int UDP_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr) { int ret; ret = sendto (socketid, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); if (ret == SOCKET_ERROR) { int err = SOCKETERRNO; if (err == NET_EWOULDBLOCK) return 0; Con_SafePrintf ("UDP_Write, sendto: %s\n", socketerror(err)); } return ret; } //============================================================================= const char *UDP_AddrToString (struct qsockaddr *addr) { static char buffer[22]; int haddr; haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); q_snprintf (buffer, sizeof(buffer), "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); return buffer; } //============================================================================= int UDP_StringToAddr (const char *string, struct qsockaddr *addr) { int ha1, ha2, ha3, ha4, hp, ipaddr; sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; addr->qsa_family = AF_INET; ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp); return 0; } //============================================================================= int UDP_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr) { socklen_t addrlen = sizeof(struct qsockaddr); in_addr_t a; memset(addr, 0, sizeof(struct qsockaddr)); if (getsockname(socketid, (struct sockaddr *)addr, &addrlen) != 0) return -1; a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; if (a == 0 || a == htonl(INADDR_LOOPBACK)) ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; return 0; } //============================================================================= int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name) { struct hostent *hostentry; hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); if (hostentry) { strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); return 0; } strcpy (name, UDP_AddrToString (addr)); return 0; } //============================================================================= int UDP_GetAddrFromName (const char *name, struct qsockaddr *addr) { struct hostent *hostentry; if (name[0] >= '0' && name[0] <= '9') return PartialIPAddress (name, addr); hostentry = gethostbyname (name); if (!hostentry) return -1; addr->qsa_family = AF_INET; ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport); ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(in_addr_t *)hostentry->h_addr_list[0]; return 0; } //============================================================================= int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) { if (addr1->qsa_family != addr2->qsa_family) return -1; if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) return -1; if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) return 1; return 0; } //============================================================================= int UDP_GetSocketPort (struct qsockaddr *addr) { return ntohs(((struct sockaddr_in *)addr)->sin_port); } int UDP_SetSocketPort (struct qsockaddr *addr, int port) { ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port); return 0; } //============================================================================= ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_codec.h�����������������������������������������������������������������0000644�0000000�0000000�00000005742�12220541170�015613� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Audio Codecs: Adapted from ioquake3 with changes. * For now, only handles streaming music, not sound effects. * * Copyright (C) 1999-2005 Id Software, Inc. * Copyright (C) 2005 Stuart Dalton <badcdev@gmail.com> * Copyright (C) 2010-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #ifndef _SND_CODEC_H_ #define _SND_CODEC_H_ typedef struct snd_info_s { int rate; int bits, width; int channels; int samples; int blocksize; int size; int dataofs; } snd_info_t; typedef enum { STREAM_NONE = -1, STREAM_INIT, STREAM_PAUSE, STREAM_PLAY } stream_status_t; typedef struct snd_codec_s snd_codec_t; typedef struct snd_stream_s { fshandle_t fh; qboolean pak; char name[MAX_QPATH]; /* name of the source file */ snd_info_t info; stream_status_t status; snd_codec_t *codec; /* codec handling this stream */ void *priv; /* data private to the codec. */ } snd_stream_t; void S_CodecInit (void); void S_CodecShutdown (void); /* Callers of the following S_CodecOpenStream* functions * are reponsible for attaching any path to the filename */ snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type); /* Decides according to the required type. */ snd_stream_t *S_CodecOpenStreamAny (const char *filename); /* Decides according to file extension. if the * name has no extension, try all available. */ snd_stream_t *S_CodecOpenStreamExt (const char *filename); /* Decides according to file extension. the name * MUST have an extension. */ void S_CodecCloseStream (snd_stream_t *stream); int S_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer); int S_CodecRewindStream (snd_stream_t *stream); snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec); void S_CodecUtilClose(snd_stream_t **stream); #define CODECTYPE_NONE 0 #define CODECTYPE_MID (1U << 0) #define CODECTYPE_MOD (1U << 1) #define CODECTYPE_FLAC (1U << 2) #define CODECTYPE_WAV (1U << 3) #define CODECTYPE_MP3 (1U << 4) #define CODECTYPE_VORBIS (1U << 5) #define CODECTYPE_OPUS (1U << 6) #define CODECTYPE_UMX (1U << 7) #define CODECTYPE_WAVE CODECTYPE_WAV #define CODECTYPE_MIDI CODECTYPE_MID int S_CodecIsAvailable (unsigned int type); /* return 1 if available, 0 if codec failed init * or -1 if no such codec is present. */ #endif /* _SND_CODEC_H_ */ ������������������������������quakespasm-0.91.0/Quake/pr_exec.c�������������������������������������������������������������������0000644�0000000�0000000�00000031501�12407762022�015312� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" typedef struct { int s; dfunction_t *f; } prstack_t; #define MAX_STACK_DEPTH 32 static prstack_t pr_stack[MAX_STACK_DEPTH]; static int pr_depth; #define LOCALSTACK_SIZE 2048 static int localstack[LOCALSTACK_SIZE]; static int localstack_used; qboolean pr_trace; dfunction_t *pr_xfunction; int pr_xstatement; int pr_argc; static const char *pr_opnames[] = { "DONE", "MUL_F", "MUL_V", "MUL_FV", "MUL_VF", "DIV", "ADD_F", "ADD_V", "SUB_F", "SUB_V", "EQ_F", "EQ_V", "EQ_S", "EQ_E", "EQ_FNC", "NE_F", "NE_V", "NE_S", "NE_E", "NE_FNC", "LE", "GE", "LT", "GT", "INDIRECT", "INDIRECT", "INDIRECT", "INDIRECT", "INDIRECT", "INDIRECT", "ADDRESS", "STORE_F", "STORE_V", "STORE_S", "STORE_ENT", "STORE_FLD", "STORE_FNC", "STOREP_F", "STOREP_V", "STOREP_S", "STOREP_ENT", "STOREP_FLD", "STOREP_FNC", "RETURN", "NOT_F", "NOT_V", "NOT_S", "NOT_ENT", "NOT_FNC", "IF", "IFNOT", "CALL0", "CALL1", "CALL2", "CALL3", "CALL4", "CALL5", "CALL6", "CALL7", "CALL8", "STATE", "GOTO", "AND", "OR", "BITAND", "BITOR" }; const char *PR_GlobalString (int ofs); const char *PR_GlobalStringNoContents (int ofs); //============================================================================= /* ================= PR_PrintStatement ================= */ static void PR_PrintStatement (dstatement_t *s) { int i; if ((unsigned int)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0])) { Con_Printf("%s ", pr_opnames[s->op]); i = strlen(pr_opnames[s->op]); for ( ; i < 10; i++) Con_Printf(" "); } if (s->op == OP_IF || s->op == OP_IFNOT) Con_Printf("%sbranch %i", PR_GlobalString(s->a), s->b); else if (s->op == OP_GOTO) { Con_Printf("branch %i", s->a); } else if ((unsigned int)(s->op-OP_STORE_F) < 6) { Con_Printf("%s", PR_GlobalString(s->a)); Con_Printf("%s", PR_GlobalStringNoContents(s->b)); } else { if (s->a) Con_Printf("%s", PR_GlobalString(s->a)); if (s->b) Con_Printf("%s", PR_GlobalString(s->b)); if (s->c) Con_Printf("%s", PR_GlobalStringNoContents(s->c)); } Con_Printf("\n"); } /* ============ PR_StackTrace ============ */ static void PR_StackTrace (void) { int i; dfunction_t *f; if (pr_depth == 0) { Con_Printf("<NO STACK>\n"); return; } pr_stack[pr_depth].f = pr_xfunction; for (i = pr_depth; i >= 0; i--) { f = pr_stack[i].f; if (!f) { Con_Printf("<NO FUNCTION>\n"); } else { Con_Printf("%12s : %s\n", PR_GetString(f->s_file), PR_GetString(f->s_name)); } } } /* ============ PR_Profile_f ============ */ void PR_Profile_f (void) { int i, num; int pmax; dfunction_t *f, *best; if (!sv.active) return; num = 0; do { pmax = 0; best = NULL; for (i = 0; i < progs->numfunctions; i++) { f = &pr_functions[i]; if (f->profile > pmax) { pmax = f->profile; best = f; } } if (best) { if (num < 10) Con_Printf("%7i %s\n", best->profile, PR_GetString(best->s_name)); num++; best->profile = 0; } } while (best); } /* ============ PR_RunError Aborts the currently executing function ============ */ void PR_RunError (const char *error, ...) { va_list argptr; char string[1024]; va_start (argptr, error); q_vsnprintf (string, sizeof(string), error, argptr); va_end (argptr); PR_PrintStatement(pr_statements + pr_xstatement); PR_StackTrace(); Con_Printf("%s\n", string); pr_depth = 0; // dump the stack so host_error can shutdown functions Host_Error("Program error"); } /* ==================== PR_EnterFunction Returns the new program statement counter ==================== */ static int PR_EnterFunction (dfunction_t *f) { int i, j, c, o; pr_stack[pr_depth].s = pr_xstatement; pr_stack[pr_depth].f = pr_xfunction; pr_depth++; if (pr_depth >= MAX_STACK_DEPTH) PR_RunError("stack overflow"); // save off any locals that the new function steps on c = f->locals; if (localstack_used + c > LOCALSTACK_SIZE) PR_RunError("PR_ExecuteProgram: locals stack overflow\n"); for (i = 0; i < c ; i++) localstack[localstack_used + i] = ((int *)pr_globals)[f->parm_start + i]; localstack_used += c; // copy parameters o = f->parm_start; for (i = 0; i < f->numparms; i++) { for (j = 0; j < f->parm_size[i]; j++) { ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0 + i*3 + j]; o++; } } pr_xfunction = f; return f->first_statement - 1; // offset the s++ } /* ==================== PR_LeaveFunction ==================== */ static int PR_LeaveFunction (void) { int i, c; if (pr_depth <= 0) Host_Error("prog stack underflow"); // Restore locals from the stack c = pr_xfunction->locals; localstack_used -= c; if (localstack_used < 0) PR_RunError("PR_ExecuteProgram: locals stack underflow"); for (i = 0; i < c; i++) ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used + i]; // up stack pr_depth--; pr_xfunction = pr_stack[pr_depth].f; return pr_stack[pr_depth].s; } /* ==================== PR_ExecuteProgram The interpretation main loop ==================== */ #define OPA ((eval_t *)&pr_globals[(unsigned short)st->a]) #define OPB ((eval_t *)&pr_globals[(unsigned short)st->b]) #define OPC ((eval_t *)&pr_globals[(unsigned short)st->c]) void PR_ExecuteProgram (func_t fnum) { eval_t *ptr; dstatement_t *st; dfunction_t *f, *newf; int profile, startprofile; edict_t *ed; int exitdepth; if (!fnum || fnum >= progs->numfunctions) { if (pr_global_struct->self) ED_Print (PROG_TO_EDICT(pr_global_struct->self)); Host_Error ("PR_ExecuteProgram: NULL function"); } f = &pr_functions[fnum]; pr_trace = false; // make a stack frame exitdepth = pr_depth; st = &pr_statements[PR_EnterFunction(f)]; startprofile = profile = 0; while (1) { st++; /* next statement */ if (++profile > 100000) { pr_xstatement = st - pr_statements; PR_RunError("runaway loop error"); } if (pr_trace) PR_PrintStatement(st); switch (st->op) { case OP_ADD_F: OPC->_float = OPA->_float + OPB->_float; break; case OP_ADD_V: OPC->vector[0] = OPA->vector[0] + OPB->vector[0]; OPC->vector[1] = OPA->vector[1] + OPB->vector[1]; OPC->vector[2] = OPA->vector[2] + OPB->vector[2]; break; case OP_SUB_F: OPC->_float = OPA->_float - OPB->_float; break; case OP_SUB_V: OPC->vector[0] = OPA->vector[0] - OPB->vector[0]; OPC->vector[1] = OPA->vector[1] - OPB->vector[1]; OPC->vector[2] = OPA->vector[2] - OPB->vector[2]; break; case OP_MUL_F: OPC->_float = OPA->_float * OPB->_float; break; case OP_MUL_V: OPC->_float = OPA->vector[0] * OPB->vector[0] + OPA->vector[1] * OPB->vector[1] + OPA->vector[2] * OPB->vector[2]; break; case OP_MUL_FV: OPC->vector[0] = OPA->_float * OPB->vector[0]; OPC->vector[1] = OPA->_float * OPB->vector[1]; OPC->vector[2] = OPA->_float * OPB->vector[2]; break; case OP_MUL_VF: OPC->vector[0] = OPB->_float * OPA->vector[0]; OPC->vector[1] = OPB->_float * OPA->vector[1]; OPC->vector[2] = OPB->_float * OPA->vector[2]; break; case OP_DIV_F: OPC->_float = OPA->_float / OPB->_float; break; case OP_BITAND: OPC->_float = (int)OPA->_float & (int)OPB->_float; break; case OP_BITOR: OPC->_float = (int)OPA->_float | (int)OPB->_float; break; case OP_GE: OPC->_float = OPA->_float >= OPB->_float; break; case OP_LE: OPC->_float = OPA->_float <= OPB->_float; break; case OP_GT: OPC->_float = OPA->_float > OPB->_float; break; case OP_LT: OPC->_float = OPA->_float < OPB->_float; break; case OP_AND: OPC->_float = OPA->_float && OPB->_float; break; case OP_OR: OPC->_float = OPA->_float || OPB->_float; break; case OP_NOT_F: OPC->_float = !OPA->_float; break; case OP_NOT_V: OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]; break; case OP_NOT_S: OPC->_float = !OPA->string || !*PR_GetString(OPA->string); break; case OP_NOT_FNC: OPC->_float = !OPA->function; break; case OP_NOT_ENT: OPC->_float = (PROG_TO_EDICT(OPA->edict) == sv.edicts); break; case OP_EQ_F: OPC->_float = OPA->_float == OPB->_float; break; case OP_EQ_V: OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]); break; case OP_EQ_S: OPC->_float = !strcmp(PR_GetString(OPA->string), PR_GetString(OPB->string)); break; case OP_EQ_E: OPC->_float = OPA->_int == OPB->_int; break; case OP_EQ_FNC: OPC->_float = OPA->function == OPB->function; break; case OP_NE_F: OPC->_float = OPA->_float != OPB->_float; break; case OP_NE_V: OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]); break; case OP_NE_S: OPC->_float = strcmp(PR_GetString(OPA->string), PR_GetString(OPB->string)); break; case OP_NE_E: OPC->_float = OPA->_int != OPB->_int; break; case OP_NE_FNC: OPC->_float = OPA->function != OPB->function; break; case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers OPB->_int = OPA->_int; break; case OP_STORE_V: OPB->vector[0] = OPA->vector[0]; OPB->vector[1] = OPA->vector[1]; OPB->vector[2] = OPA->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *)((byte *)sv.edicts + OPB->_int); ptr->_int = OPA->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + OPB->_int); ptr->vector[0] = OPA->vector[0]; ptr->vector[1] = OPA->vector[1]; ptr->vector[2] = OPA->vector[2]; break; case OP_ADDRESS: ed = PROG_TO_EDICT(OPA->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) { pr_xstatement = st - pr_statements; PR_RunError("assignment to world entity"); } OPC->_int = (byte *)((int *)&ed->v + OPB->_int) - (byte *)sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(OPA->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif OPC->_int = ((eval_t *)((int *)&ed->v + OPB->_int))->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(OPA->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif ptr = (eval_t *)((int *)&ed->v + OPB->_int); OPC->vector[0] = ptr->vector[0]; OPC->vector[1] = ptr->vector[1]; OPC->vector[2] = ptr->vector[2]; break; case OP_IFNOT: if (!OPA->_int) st += st->b - 1; /* -1 to offset the st++ */ break; case OP_IF: if (OPA->_int) st += st->b - 1; /* -1 to offset the st++ */ break; case OP_GOTO: st += st->a - 1; /* -1 to offset the st++ */ break; case OP_CALL0: case OP_CALL1: case OP_CALL2: case OP_CALL3: case OP_CALL4: case OP_CALL5: case OP_CALL6: case OP_CALL7: case OP_CALL8: pr_xfunction->profile += profile - startprofile; startprofile = profile; pr_xstatement = st - pr_statements; pr_argc = st->op - OP_CALL0; if (!OPA->function) PR_RunError("NULL function"); newf = &pr_functions[OPA->function]; if (newf->first_statement < 0) { // Built-in function int i = -newf->first_statement; if (i >= pr_numbuiltins) PR_RunError("Bad builtin call number %d", i); pr_builtins[i](); break; } // Normal function st = &pr_statements[PR_EnterFunction(newf)]; break; case OP_DONE: case OP_RETURN: pr_xfunction->profile += profile - startprofile; startprofile = profile; pr_xstatement = st - pr_statements; pr_globals[OFS_RETURN] = pr_globals[(unsigned short)st->a]; pr_globals[OFS_RETURN + 1] = pr_globals[(unsigned short)st->a + 1]; pr_globals[OFS_RETURN + 2] = pr_globals[(unsigned short)st->a + 2]; st = &pr_statements[PR_LeaveFunction()]; if (pr_depth == exitdepth) { // Done return; } break; case OP_STATE: ed = PROG_TO_EDICT(pr_global_struct->self); ed->v.nextthink = pr_global_struct->time + 0.1; ed->v.frame = OPA->_float; ed->v.think = OPB->function; break; default: pr_xstatement = st - pr_statements; PR_RunError("Bad opcode %i", st->op); } } /* end of while(1) loop */ } #undef OPA #undef OPB #undef OPC �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_flac.c������������������������������������������������������������������0000644�0000000�0000000�00000026574�12471320271�015451� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * fLaC streaming music support, loosely based QuakeForge implementation * with modifications. requires libFLAC >= 1.0.4 at compile and runtime. * * Copyright (C) 2005 Bill Currie <bill@taniwha.org> * Copyright (C) 2013 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #include "quakedef.h" #if defined(USE_CODEC_FLAC) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_flac.h" #undef LEGACY_FLAC #include <FLAC/stream_decoder.h> /* FLAC 1.1.3 has FLAC_API_VERSION_CURRENT == 8 */ #if !defined(FLAC_API_VERSION_CURRENT) || ((FLAC_API_VERSION_CURRENT+0) < 8) #define LEGACY_FLAC #include <FLAC/seekable_stream_decoder.h> #endif #include <FLAC/metadata.h> #ifdef LEGACY_FLAC #define FLAC__StreamDecoder FLAC__SeekableStreamDecoder #define FLAC__StreamDecoderReadStatus FLAC__SeekableStreamDecoderReadStatus #define FLAC__StreamDecoderSeekStatus FLAC__SeekableStreamDecoderSeekStatus #define FLAC__StreamDecoderTellStatus FLAC__SeekableStreamDecoderTellStatus #define FLAC__StreamDecoderLengthStatus FLAC__SeekableStreamDecoderLengthStatus #define FLAC__stream_decoder_new FLAC__seekable_stream_decoder_new #define FLAC__stream_decoder_finish FLAC__seekable_stream_decoder_finish #define FLAC__stream_decoder_delete FLAC__seekable_stream_decoder_delete #define FLAC__stream_decoder_process_single FLAC__seekable_stream_decoder_process_single #define FLAC__stream_decoder_seek_absolute FLAC__seekable_stream_decoder_seek_absolute #define FLAC__stream_decoder_process_until_end_of_metadata FLAC__seekable_stream_decoder_process_until_end_of_metadata #define FLAC__stream_decoder_get_state FLAC__seekable_stream_decoder_get_state #define FLAC__STREAM_DECODER_INIT_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_OK #define FLAC__STREAM_DECODER_READ_STATUS_CONTINUE FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK #define FLAC__STREAM_DECODER_READ_STATUS_ABORT FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR #define FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK /* !!! */ #define FLAC__STREAM_DECODER_WRITE_STATUS_ABORT FLAC__STREAM_DECODER_WRITE_STATUS_ABORT #define FLAC__STREAM_DECODER_SEEK_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK #define FLAC__STREAM_DECODER_SEEK_STATUS_ERROR FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR #define FLAC__STREAM_DECODER_TELL_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK #define FLAC__STREAM_DECODER_TELL_STATUS_ERROR FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR #define FLAC__STREAM_DECODER_LENGTH_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK #endif typedef struct { FLAC__StreamDecoder *decoder; fshandle_t *file; snd_info_t *info; byte *buffer; int size, pos, error; } flacfile_t; /* CALLBACK FUNCTIONS: */ static void flac_error_func (const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; ff->error = -1; Con_Printf ("FLAC: decoder error %i\n", status); } static FLAC__StreamDecoderReadStatus flac_read_func (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; if (*bytes > 0) { *bytes = FS_fread(buffer, 1, *bytes, ff->file); if (FS_ferror(ff->file)) return FLAC__STREAM_DECODER_READ_STATUS_ABORT; if (*bytes == 0) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } static FLAC__StreamDecoderSeekStatus flac_seek_func (const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; if (FS_fseek(ff->file, (long)absolute_byte_offset, SEEK_SET) < 0) return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; return FLAC__STREAM_DECODER_SEEK_STATUS_OK; } static FLAC__StreamDecoderTellStatus flac_tell_func (const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; long pos = FS_ftell (ff->file); if (pos < 0) return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; *absolute_byte_offset = (FLAC__uint64) pos; return FLAC__STREAM_DECODER_TELL_STATUS_OK; } static FLAC__StreamDecoderLengthStatus flac_length_func (const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; *stream_length = (FLAC__uint64) FS_filelength (ff->file); return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; } static FLAC__bool flac_eof_func (const FLAC__StreamDecoder *decoder, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; if (FS_feof (ff->file)) return true; return false; } static FLAC__StreamDecoderWriteStatus flac_write_func (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; if (!ff->buffer) { ff->buffer = (byte *) malloc (ff->info->blocksize * ff->info->channels * ff->info->width); if (!ff->buffer) { ff->error = -1; /* needn't set this here, but... */ Con_Printf("Insufficient memory for fLaC audio\n"); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } } if (ff->info->channels == 1) { unsigned i; const FLAC__int32 *in = buffer[0]; if (ff->info->bits == 8) { byte *out = ff->buffer; for (i = 0; i < frame->header.blocksize; i++) *out++ = *in++ + 128; } else { short *out = (short *) ff->buffer; for (i = 0; i < frame->header.blocksize; i++) *out++ = *in++; } } else { unsigned i; const FLAC__int32 *li = buffer[0]; const FLAC__int32 *ri = buffer[1]; if (ff->info->bits == 8) { char *lo = (char *) ff->buffer + 0; char *ro = (char *) ff->buffer + 1; for (i = 0; i < frame->header.blocksize; i++, lo++, ro++) { *lo++ = *li++ + 128; *ro++ = *ri++ + 128; } } else { short *lo = (short *) ff->buffer + 0; short *ro = (short *) ff->buffer + 1; for (i = 0; i < frame->header.blocksize; i++, lo++, ro++) { *lo++ = *li++; *ro++ = *ri++; } } } ff->size = frame->header.blocksize * ff->info->width * ff->info->channels; ff->pos = 0; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } static void flac_meta_func (const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { ff->info->rate = metadata->data.stream_info.sample_rate; ff->info->bits = metadata->data.stream_info.bits_per_sample; ff->info->width = ff->info->bits / 8; ff->info->channels = metadata->data.stream_info.channels; ff->info->blocksize = metadata->data.stream_info.max_blocksize; ff->info->dataofs = 0; /* got the STREAMINFO metadata */ } } static qboolean S_FLAC_CodecInitialize (void) { return true; } static void S_FLAC_CodecShutdown (void) { } static qboolean S_FLAC_CodecOpenStream (snd_stream_t *stream) { flacfile_t *ff; int rc; ff = (flacfile_t *) Z_Malloc(sizeof(flacfile_t)); ff->decoder = FLAC__stream_decoder_new (); if (ff->decoder == NULL) { Con_Printf("Unable to create fLaC decoder\n"); goto _fail; } stream->priv = ff; ff->info = & stream->info; ff->file = & stream->fh; ff->info->dataofs = -1; /* check for STREAMINFO metadata existence */ #ifdef LEGACY_FLAC FLAC__seekable_stream_decoder_set_error_callback (ff->decoder, flac_error_func); FLAC__seekable_stream_decoder_set_read_callback (ff->decoder, flac_read_func); FLAC__seekable_stream_decoder_set_seek_callback (ff->decoder, flac_seek_func); FLAC__seekable_stream_decoder_set_tell_callback (ff->decoder, flac_tell_func); FLAC__seekable_stream_decoder_set_length_callback (ff->decoder, flac_length_func); FLAC__seekable_stream_decoder_set_eof_callback (ff->decoder, flac_eof_func); FLAC__seekable_stream_decoder_set_write_callback (ff->decoder, flac_write_func); FLAC__seekable_stream_decoder_set_metadata_callback (ff->decoder, flac_meta_func); FLAC__seekable_stream_decoder_set_client_data (ff->decoder, ff); rc = FLAC__seekable_stream_decoder_init (ff->decoder); #else rc = FLAC__stream_decoder_init_stream(ff->decoder, flac_read_func, flac_seek_func, flac_tell_func, flac_length_func, flac_eof_func, flac_write_func, flac_meta_func, flac_error_func, ff); #endif if (rc != FLAC__STREAM_DECODER_INIT_STATUS_OK) /* unlikely */ { Con_Printf ("FLAC: decoder init error %i\n", rc); goto _fail; } rc = FLAC__stream_decoder_process_until_end_of_metadata (ff->decoder); if (rc == false || ff->error) { rc = FLAC__stream_decoder_get_state(ff->decoder); Con_Printf("%s not a valid flac file? (decoder state %i)\n", stream->name, rc); goto _fail; } if (ff->info->dataofs < 0) { Con_Printf("%s has no STREAMINFO\n", stream->name); goto _fail; } if (ff->info->bits != 8 && ff->info->bits != 16) { Con_Printf("%s is not 8 or 16 bit\n", stream->name); goto _fail; } if (ff->info->channels != 1 && ff->info->channels != 2) { Con_Printf("Unsupported number of channels %d in %s\n", ff->info->channels, stream->name); goto _fail; } return true; _fail: if (ff->decoder) { FLAC__stream_decoder_finish (ff->decoder); FLAC__stream_decoder_delete (ff->decoder); } Z_Free(ff); return false; } static int S_FLAC_CodecReadStream (snd_stream_t *stream, int len, void *buffer) { flacfile_t *ff = (flacfile_t *) stream->priv; byte *buf = (byte *) buffer; int count = 0; while (len) { int res = 0; if (ff->size == ff->pos) FLAC__stream_decoder_process_single (ff->decoder); if (ff->error) return -1; res = ff->size - ff->pos; if (res > len) res = len; if (res > 0) { memcpy (buf, ff->buffer + ff->pos, res); count += res; len -= res; buf += res; ff->pos += res; } else if (res < 0) { /* error */ return -1; } else { Con_DPrintf ("FLAC: EOF\n"); break; } } return count; } static void S_FLAC_CodecCloseStream (snd_stream_t *stream) { flacfile_t *ff = (flacfile_t *) stream->priv; FLAC__stream_decoder_finish (ff->decoder); FLAC__stream_decoder_delete (ff->decoder); if (ff->buffer) free(ff->buffer); Z_Free(ff); S_CodecUtilClose(&stream); } static int S_FLAC_CodecRewindStream (snd_stream_t *stream) { flacfile_t *ff = (flacfile_t *) stream->priv; ff->pos = ff->size = 0; if (FLAC__stream_decoder_seek_absolute(ff->decoder, 0)) return 0; return -1; } snd_codec_t flac_codec = { CODECTYPE_FLAC, true, /* always available. */ "flac", S_FLAC_CodecInitialize, S_FLAC_CodecShutdown, S_FLAC_CodecOpenStream, S_FLAC_CodecReadStream, S_FLAC_CodecRewindStream, S_FLAC_CodecCloseStream, NULL }; #endif /* USE_CODEC_FLAC */ ������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sys.h�����������������������������������������������������������������������0000644�0000000�0000000�00000003673�12407762022�014521� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_SYS_H #define _QUAKE_SYS_H // sys.h -- non-portable functions void Sys_Init (void); // // file IO // // returns the file size or -1 if file is not present. // the file should be in BINARY mode for stupid OSs that care int Sys_FileOpenRead (const char *path, int *hndl); int Sys_FileOpenWrite (const char *path); void Sys_FileClose (int handle); void Sys_FileSeek (int handle, int position); int Sys_FileRead (int handle, void *dest, int count); int Sys_FileWrite (int handle,const void *data, int count); int Sys_FileTime (const char *path); void Sys_mkdir (const char *path); // // system IO // void Sys_Error (const char *error, ...) __attribute__((__format__(__printf__,1,2), __noreturn__)); // an error will cause the entire program to exit void Sys_Printf (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); // send text to the console void Sys_Quit (void) __attribute__((__noreturn__)); double Sys_DoubleTime (void); const char *Sys_ConsoleInput (void); void Sys_Sleep (unsigned long msecs); // yield for about 'msecs' milliseconds. void Sys_SendKeyEvents (void); // Perform Key_Event () callbacks until the input que is empty #endif /* _QUAKE_SYS_H */ ���������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_model.h������������������������������������������������������������������0000644�0000000�0000000�00000027525�12577611311�015471� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __MODEL__ #define __MODEL__ #include "modelgen.h" #include "spritegn.h" /* d*_t structures are on-disk representations m*_t structures are in-memory */ // entity effects #define EF_BRIGHTFIELD 1 #define EF_MUZZLEFLASH 2 #define EF_BRIGHTLIGHT 4 #define EF_DIMLIGHT 8 /* ============================================================================== BRUSH MODELS ============================================================================== */ // // in memory representation // // !!! if this is changed, it must be changed in asm_draw.h too !!! typedef struct { vec3_t position; } mvertex_t; #define SIDE_FRONT 0 #define SIDE_BACK 1 #define SIDE_ON 2 // plane_t structure // !!! if this is changed, it must be changed in asm_i386.h too !!! typedef struct mplane_s { vec3_t normal; float dist; byte type; // for texture axis selection and fast side tests byte signbits; // signx + signy<<1 + signz<<1 byte pad[2]; } mplane_t; // ericw -- each texture has two chains, so we can clear the model chains // without affecting the world typedef enum { chain_world = 0, chain_model = 1 } texchain_t; typedef struct texture_s { char name[16]; unsigned width, height; struct gltexture_s *gltexture; //johnfitz -- pointer to gltexture struct gltexture_s *fullbright; //johnfitz -- fullbright mask texture struct gltexture_s *warpimage; //johnfitz -- for water animation qboolean update_warp; //johnfitz -- update warp this frame struct msurface_s *texturechains[2]; // for texture chains int anim_total; // total tenths in sequence ( 0 = no) int anim_min, anim_max; // time for this frame min <=time< max struct texture_s *anim_next; // in the animation sequence struct texture_s *alternate_anims; // bmodels in frmae 1 use these unsigned offsets[MIPLEVELS]; // four mip maps stored } texture_t; #define SURF_PLANEBACK 2 #define SURF_DRAWSKY 4 #define SURF_DRAWSPRITE 8 #define SURF_DRAWTURB 0x10 #define SURF_DRAWTILED 0x20 #define SURF_DRAWBACKGROUND 0x40 #define SURF_UNDERWATER 0x80 #define SURF_NOTEXTURE 0x100 //johnfitz #define SURF_DRAWFENCE 0x200 #define SURF_DRAWLAVA 0x400 #define SURF_DRAWSLIME 0x800 #define SURF_DRAWTELE 0x1000 #define SURF_DRAWWATER 0x2000 // !!! if this is changed, it must be changed in asm_draw.h too !!! typedef struct { unsigned int v[2]; unsigned int cachededgeoffset; } medge_t; typedef struct { float vecs[2][4]; float mipadjust; texture_t *texture; int flags; } mtexinfo_t; #define VERTEXSIZE 7 typedef struct glpoly_s { struct glpoly_s *next; struct glpoly_s *chain; int numverts; float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) } glpoly_t; typedef struct msurface_s { int visframe; // should be drawn when node is crossed qboolean culled; // johnfitz -- for frustum culling float mins[3]; // johnfitz -- for frustum culling float maxs[3]; // johnfitz -- for frustum culling mplane_t *plane; int flags; int firstedge; // look up in model->surfedges[], negative numbers int numedges; // are backwards edges short texturemins[2]; short extents[2]; int light_s, light_t; // gl lightmap coordinates glpoly_t *polys; // multiple if warped struct msurface_s *texturechain; mtexinfo_t *texinfo; int vbo_firstvert; // index of this surface's first vert in the VBO // lighting info int dlightframe; unsigned int dlightbits[(MAX_DLIGHTS + 31) >> 5]; // int is 32 bits, need an array for MAX_DLIGHTS > 32 int lightmaptexturenum; byte styles[MAXLIGHTMAPS]; int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap qboolean cached_dlight; // true if dynamic light in cache byte *samples; // [numstyles*surfsize] } msurface_t; typedef struct mnode_s { // common with leaf int contents; // 0, to differentiate from leafs int visframe; // node needs to be traversed if current float minmaxs[6]; // for bounding box culling struct mnode_s *parent; // node specific mplane_t *plane; struct mnode_s *children[2]; unsigned int firstsurface; unsigned int numsurfaces; } mnode_t; typedef struct mleaf_s { // common with node int contents; // wil be a negative contents number int visframe; // node needs to be traversed if current float minmaxs[6]; // for bounding box culling struct mnode_s *parent; // leaf specific byte *compressed_vis; efrag_t *efrags; msurface_t **firstmarksurface; int nummarksurfaces; int key; // BSP sequence number for leaf's contents byte ambient_sound_level[NUM_AMBIENTS]; } mleaf_t; //johnfitz -- for clipnodes>32k typedef struct mclipnode_s { int planenum; int children[2]; // negative numbers are contents } mclipnode_t; //johnfitz // !!! if this is changed, it must be changed in asm_i386.h too !!! typedef struct { mclipnode_t *clipnodes; //johnfitz -- was dclipnode_t mplane_t *planes; int firstclipnode; int lastclipnode; vec3_t clip_mins; vec3_t clip_maxs; } hull_t; /* ============================================================================== SPRITE MODELS ============================================================================== */ // FIXME: shorten these? typedef struct mspriteframe_s { int width, height; float up, down, left, right; float smax, tmax; //johnfitz -- image might be padded struct gltexture_s *gltexture; } mspriteframe_t; typedef struct { int numframes; float *intervals; mspriteframe_t *frames[1]; } mspritegroup_t; typedef struct { spriteframetype_t type; mspriteframe_t *frameptr; } mspriteframedesc_t; typedef struct { int type; int maxwidth; int maxheight; int numframes; float beamlength; // remove? void *cachespot; // remove? mspriteframedesc_t frames[1]; } msprite_t; /* ============================================================================== ALIAS MODELS Alias models are position independent, so the cache manager can move them. ============================================================================== */ //-- from RMQEngine // split out to keep vertex sizes down typedef struct aliasmesh_s { float st[2]; unsigned short vertindex; } aliasmesh_t; typedef struct meshxyz_s { byte xyz[4]; signed char normal[4]; } meshxyz_t; typedef struct meshst_s { float st[2]; } meshst_t; //-- typedef struct { int firstpose; int numposes; float interval; trivertx_t bboxmin; trivertx_t bboxmax; int frame; char name[16]; } maliasframedesc_t; typedef struct { trivertx_t bboxmin; trivertx_t bboxmax; int frame; } maliasgroupframedesc_t; typedef struct { int numframes; int intervals; maliasgroupframedesc_t frames[1]; } maliasgroup_t; // !!! if this is changed, it must be changed in asm_draw.h too !!! typedef struct mtriangle_s { int facesfront; int vertindex[3]; } mtriangle_t; #define MAX_SKINS 32 typedef struct { int ident; int version; vec3_t scale; vec3_t scale_origin; float boundingradius; vec3_t eyeposition; int numskins; int skinwidth; int skinheight; int numverts; int numtris; int numframes; synctype_t synctype; int flags; float size; //ericw -- used to populate vbo int numverts_vbo; // number of verts with unique x,y,z,s,t intptr_t meshdesc; // offset into extradata: numverts_vbo aliasmesh_t int numindexes; intptr_t indexes; // offset into extradata: numindexes unsigned shorts intptr_t vertexes; // offset into extradata: numposes*vertsperframe trivertx_t //ericw -- int numposes; int poseverts; int posedata; // numposes*poseverts trivert_t int commands; // gl command list with embedded s/t struct gltexture_s *gltextures[MAX_SKINS][4]; //johnfitz struct gltexture_s *fbtextures[MAX_SKINS][4]; //johnfitz int texels[MAX_SKINS]; // only for player skins maliasframedesc_t frames[1]; // variable sized } aliashdr_t; #define MAXALIASVERTS 2000 //johnfitz -- was 1024 #define MAXALIASFRAMES 256 #define MAXALIASTRIS 2048 extern aliashdr_t *pheader; extern stvert_t stverts[MAXALIASVERTS]; extern mtriangle_t triangles[MAXALIASTRIS]; extern trivertx_t *poseverts[MAXALIASFRAMES]; //=================================================================== // // Whole model // typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t; #define EF_ROCKET 1 // leave a trail #define EF_GRENADE 2 // leave a trail #define EF_GIB 4 // leave a trail #define EF_ROTATE 8 // rotate (bonus items) #define EF_TRACER 16 // green split trail #define EF_ZOMGIB 32 // small blood trail #define EF_TRACER2 64 // orange split trail + rotate #define EF_TRACER3 128 // purple trail //johnfitz -- extra flags for rendering #define MOD_NOLERP 256 //don't lerp when animating #define MOD_NOSHADOW 512 //don't cast a shadow #define MOD_FBRIGHTHACK 1024 //when fullbrights are disabled, use a hack to render this model brighter //johnfitz typedef struct qmodel_s { char name[MAX_QPATH]; unsigned int path_id; // path id of the game directory // that this model came from qboolean needload; // bmodels and sprites don't cache normally modtype_t type; int numframes; synctype_t synctype; int flags; // // volume occupied by the model graphics // vec3_t mins, maxs; vec3_t ymins, ymaxs; //johnfitz -- bounds for entities with nonzero yaw vec3_t rmins, rmaxs; //johnfitz -- bounds for entities with nonzero pitch or roll //johnfitz -- removed float radius; // // solid volume for clipping // qboolean clipbox; vec3_t clipmins, clipmaxs; // // brush model // int firstmodelsurface, nummodelsurfaces; int numsubmodels; dmodel_t *submodels; int numplanes; mplane_t *planes; int numleafs; // number of visible leafs, not counting 0 mleaf_t *leafs; int numvertexes; mvertex_t *vertexes; int numedges; medge_t *edges; int numnodes; mnode_t *nodes; int numtexinfo; mtexinfo_t *texinfo; int numsurfaces; msurface_t *surfaces; int numsurfedges; int *surfedges; int numclipnodes; mclipnode_t *clipnodes; //johnfitz -- was dclipnode_t int nummarksurfaces; msurface_t **marksurfaces; hull_t hulls[MAX_MAP_HULLS]; int numtextures; texture_t **textures; byte *visdata; byte *lightdata; char *entities; int bspversion; // // alias model // GLuint meshvbo; GLuint meshindexesvbo; int vboindexofs; // offset in vbo of the hdr->numindexes unsigned shorts int vboxyzofs; // offset in vbo of hdr->numposes*hdr->numverts_vbo meshxyz_t int vbostofs; // offset in vbo of hdr->numverts_vbo meshst_t // // additional model data // cache_user_t cache; // only access through Mod_Extradata } qmodel_t; //============================================================================ void Mod_Init (void); void Mod_ClearAll (void); void Mod_ResetAll (void); // for gamedir changes (Host_Game_f) qmodel_t *Mod_ForName (const char *name, qboolean crash); void *Mod_Extradata (qmodel_t *mod); // handles caching void Mod_TouchModel (const char *name); mleaf_t *Mod_PointInLeaf (float *p, qmodel_t *model); byte *Mod_LeafPVS (mleaf_t *leaf, qmodel_t *model); void Mod_SetExtraFlags (qmodel_t *mod); #endif // __MODEL__ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/q_sound.h�������������������������������������������������������������������0000644�0000000�0000000�00000012520�12407762022�015342� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sound.h -- client sound i/o functions #ifndef __QUAKE_SOUND__ #define __QUAKE_SOUND__ /* !!! if this is changed, it must be changed in asm_i386.h too !!! */ typedef struct { int left; int right; } portable_samplepair_t; typedef struct sfx_s { char name[MAX_QPATH]; cache_user_t cache; } sfx_t; /* !!! if this is changed, it must be changed in asm_i386.h too !!! */ typedef struct { int length; int loopstart; int speed; int width; int stereo; byte data[1]; /* variable sized */ } sfxcache_t; typedef struct { int channels; int samples; /* mono samples in buffer */ int submission_chunk; /* don't mix less than this # */ int samplepos; /* in mono samples */ int samplebits; int signed8; /* device opened for S8 format? (e.g. Amiga AHI) */ int speed; unsigned char *buffer; } dma_t; /* !!! if this is changed, it must be changed in asm_i386.h too !!! */ typedef struct { sfx_t *sfx; /* sfx number */ int leftvol; /* 0-255 volume */ int rightvol; /* 0-255 volume */ int end; /* end time in global paintsamples */ int pos; /* sample position in sfx */ int looping; /* where to loop, -1 = no looping */ int entnum; /* to allow overriding a specific sound */ int entchannel; vec3_t origin; /* origin of sound effect */ vec_t dist_mult; /* distance multiplier (attenuation/clipK) */ int master_vol; /* 0-255 master volume */ } channel_t; #define WAV_FORMAT_PCM 1 typedef struct { int rate; int width; int channels; int loopstart; int samples; int dataofs; /* chunk starts this many bytes from file start */ } wavinfo_t; void S_Init (void); void S_Startup (void); void S_Shutdown (void); void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation); void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation); void S_StopSound (int entnum, int entchannel); void S_StopAllSounds(qboolean clear); void S_ClearBuffer (void); void S_Update (vec3_t origin, vec3_t forward, vec3_t right, vec3_t up); void S_ExtraUpdate (void); void S_BlockSound (void); void S_UnblockSound (void); sfx_t *S_PrecacheSound (const char *sample); void S_TouchSound (const char *sample); void S_ClearPrecache (void); void S_BeginPrecaching (void); void S_EndPrecaching (void); void S_PaintChannels (int endtime); void S_InitPaintChannels (void); /* picks a channel based on priorities, empty slots, number of channels */ channel_t *SND_PickChannel (int entnum, int entchannel); /* spatializes a channel */ void SND_Spatialize (channel_t *ch); /* music stream support */ void S_RawSamples(int samples, int rate, int width, int channels, byte * data, float volume); /* Expects data in signed 16 bit, or unsigned 8 bit format. */ /* initializes cycling through a DMA buffer and returns information on it */ qboolean SNDDMA_Init(dma_t *dma); /* gets the current DMA position */ int SNDDMA_GetDMAPos(void); /* shutdown the DMA xfer. */ void SNDDMA_Shutdown(void); /* validates & locks the dma buffer */ void SNDDMA_LockBuffer(void); /* unlocks the dma buffer / sends sound to the device */ void SNDDMA_Submit(void); /* blocks sound output upon window focus loss */ void SNDDMA_BlockSound(void); /* unblocks the output upon window focus gain */ void SNDDMA_UnblockSound(void); /* ==================================================================== * User-setable variables * ==================================================================== */ #define MAX_CHANNELS 1024 // ericw -- was 512 /* johnfitz -- was 128 */ #define MAX_DYNAMIC_CHANNELS 128 /* johnfitz -- was 8 */ extern channel_t snd_channels[MAX_CHANNELS]; /* 0 to MAX_DYNAMIC_CHANNELS-1 = normal entity sounds * MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc * MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds */ extern volatile dma_t *shm; extern int total_channels; extern int soundtime; extern int paintedtime; extern int s_rawend; extern vec3_t listener_origin; extern vec3_t listener_forward; extern vec3_t listener_right; extern vec3_t listener_up; extern cvar_t sndspeed; extern cvar_t snd_mixspeed; extern cvar_t snd_filterquality; extern cvar_t sfxvolume; extern cvar_t loadas8bit; #define MAX_RAW_SAMPLES 8192 extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; extern cvar_t bgmvolume; void S_LocalSound (const char *name); sfxcache_t *S_LoadSound (sfx_t *s); wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength); void SND_InitScaletable (void); #endif /* __QUAKE_SOUND__ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_sdl.c�������������������������������������������������������������������0000644�0000000�0000000�00000012447�12474074263�015332� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * snd_sdl.c - SDL audio driver for Hexen II: Hammer of Thyrion (uHexen2) * based on implementations found in the quakeforge and ioquake3 projects. * * Copyright (C) 1999-2005 Id Software, Inc. * Copyright (C) 2005-2012 O.Sezer <sezero@users.sourceforge.net> * Copyright (C) 2010-2014 QuakeSpasm developers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #include "quakedef.h" #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif static int buffersize; static void paint_audio (void *unused, Uint8 *stream, int len) { int pos, tobufend; int len1, len2; if (!shm) { /* shouldn't happen, but just in case */ memset(stream, 0, len); return; } pos = (shm->samplepos * (shm->samplebits / 8)); if (pos >= buffersize) shm->samplepos = pos = 0; tobufend = buffersize - pos; /* bytes to buffer's end. */ len1 = len; len2 = 0; if (len1 > tobufend) { len1 = tobufend; len2 = len - len1; } memcpy(stream, shm->buffer + pos, len1); if (len2 <= 0) { shm->samplepos += (len1 / (shm->samplebits / 8)); } else { /* wraparound? */ memcpy(stream + len1, shm->buffer, len2); shm->samplepos = (len2 / (shm->samplebits / 8)); } if (shm->samplepos >= buffersize) shm->samplepos = 0; } qboolean SNDDMA_Init (dma_t *dma) { SDL_AudioSpec desired, obtained; int tmp, val; char drivername[128]; if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { Con_Printf("Couldn't init SDL audio: %s\n", SDL_GetError()); return false; } /* Set up the desired format */ desired.freq = tmp = snd_mixspeed.value; desired.format = (loadas8bit.value) ? AUDIO_U8 : AUDIO_S16SYS; desired.channels = 2; /* = desired_channels; */ if (desired.freq <= 11025) desired.samples = 256; else if (desired.freq <= 22050) desired.samples = 512; else if (desired.freq <= 44100) desired.samples = 1024; else if (desired.freq <= 56000) desired.samples = 2048; /* for 48 kHz */ else desired.samples = 4096; /* for 96 kHz */ desired.callback = paint_audio; desired.userdata = NULL; /* Open the audio device */ if (SDL_OpenAudio(&desired, &obtained) == -1) { Con_Printf("Couldn't open SDL audio: %s\n", SDL_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); return false; } /* Make sure we can support the audio format */ switch (obtained.format) { case AUDIO_S8: /* maybe needed by AHI */ case AUDIO_U8: case AUDIO_S16SYS: /* Supported */ break; default: Con_Printf ("Unsupported audio format received (%u)\n", obtained.format); SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); return false; } memset ((void *) dma, 0, sizeof(dma_t)); shm = dma; /* Fill the audio DMA information block */ shm->samplebits = (obtained.format & 0xFF); /* first byte of format is bits */ shm->signed8 = (obtained.format == AUDIO_S8); if (obtained.freq != tmp) Con_Printf ("Warning: Rate set (%d) didn't match requested rate (%d)!\n", obtained.freq, tmp); shm->speed = obtained.freq; shm->channels = obtained.channels; tmp = (obtained.samples * obtained.channels) * 10; if (tmp & (tmp - 1)) { /* make it a power of two */ val = 1; while (val < tmp) val <<= 1; tmp = val; } shm->samples = tmp; shm->samplepos = 0; shm->submission_chunk = 1; Con_Printf ("SDL audio spec : %d Hz, %d samples, %d channels\n", obtained.freq, obtained.samples, obtained.channels); #if defined(USE_SDL2) { const char *driver = SDL_GetCurrentAudioDriver(); const char *device = SDL_GetAudioDeviceName(0, SDL_FALSE); q_snprintf(drivername, sizeof(drivername), "%s - %s", driver != NULL ? driver : "(UNKNOWN)", device != NULL ? device : "(UNKNOWN)"); } #else if (SDL_AudioDriverName(drivername, sizeof(drivername)) == NULL) strcpy(drivername, "(UNKNOWN)"); #endif buffersize = shm->samples * (shm->samplebits / 8); Con_Printf ("SDL audio driver: %s, %d bytes buffer\n", drivername, buffersize); shm->buffer = (unsigned char *) calloc (1, buffersize); if (!shm->buffer) { SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); shm = NULL; Con_Printf ("Failed allocating memory for SDL audio\n"); return false; } SDL_PauseAudio(0); return true; } int SNDDMA_GetDMAPos (void) { return shm->samplepos; } void SNDDMA_Shutdown (void) { if (shm) { Con_Printf ("Shutting down SDL sound\n"); SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); if (shm->buffer) free (shm->buffer); shm->buffer = NULL; shm = NULL; } } void SNDDMA_LockBuffer (void) { SDL_LockAudio (); } void SNDDMA_Submit (void) { SDL_UnlockAudio(); } void SNDDMA_BlockSound (void) { SDL_PauseAudio(1); } void SNDDMA_UnblockSound (void) { SDL_PauseAudio(0); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/build_cross_osx.sh����������������������������������������������������������0000755�0000000�0000000�00000002641�12021217500�017250� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh rm -f quakespasm.ppc \ quakespasm.x86 \ quakespasm.x86_64 \ QuakeSpasm make clean OLDPATH=$PATH MAKE_CMD=make OSXBUILD=1 export OSXBUILD STRIP=/bin/true export STRIP # ppc PATH=/opt/cross_osx-ppc/bin:$OLDPATH CC=powerpc-apple-darwin9-gcc AS=powerpc-apple-darwin9-as AR=powerpc-apple-darwin9-ar RANLIB=powerpc-apple-darwin9-ranlib LIPO=powerpc-apple-darwin9-lipo export PATH CC AS AR RANLIB LIPO $MAKE_CMD MACH_TYPE=ppc -f Makefile.darwin $* || exit 1 powerpc-apple-darwin9-strip -S quakespasm || exit 1 mv quakespasm quakespasm.ppc || exit 1 $MAKE_CMD clean # x86 PATH=/opt/cross_osx-x86/bin:$OLDPATH CC=i686-apple-darwin9-gcc AS=i686-apple-darwin9-as AR=i686-apple-darwin9-ar RANLIB=i686-apple-darwin9-ranlib LIPO=i686-apple-darwin9-lipo export PATH CC AS AR RANLIB LIPO $MAKE_CMD MACH_TYPE=x86 -f Makefile.darwin $* || exit 1 i686-apple-darwin9-strip -S quakespasm || exit 1 mv quakespasm quakespasm.x86 || exit 1 $MAKE_CMD clean # x86_64 PATH=/opt/cross_osx-x86_64/usr/bin:$OLDPATH CC=x86_64-apple-darwin9-gcc AS=x86_64-apple-darwin9-as AR=x86_64-apple-darwin9-ar RANLIB=x86_64-apple-darwin9-ranlib LIPO=x86_64-apple-darwin9-lipo export PATH CC AS AR RANLIB LIPO $MAKE_CMD MACH_TYPE=x86_64 -f Makefile.darwin $* || exit 1 x86_64-apple-darwin9-strip -S quakespasm || exit 1 mv quakespasm quakespasm.x86_64 || exit 1 $MAKE_CMD clean $LIPO -create -o QuakeSpasm quakespasm.ppc quakespasm.x86 quakespasm.x86_64 || exit 1 �����������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_dgrm.h������������������������������������������������������������������0000644�0000000�0000000�00000002634�12407762022�015476� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __NET_DATAGRAM_H #define __NET_DATAGRAM_H int Datagram_Init (void); void Datagram_Listen (qboolean state); void Datagram_SearchForHosts (qboolean xmit); qsocket_t *Datagram_Connect (const char *host); qsocket_t *Datagram_CheckNewConnections (void); int Datagram_GetMessage (qsocket_t *sock); int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data); int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data); qboolean Datagram_CanSendMessage (qsocket_t *sock); qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock); void Datagram_Close (qsocket_t *sock); void Datagram_Shutdown (void); #endif /* __NET_DATAGRAM_H */ ����������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_warp_sin.h���������������������������������������������������������������0000644�0000000�0000000�00000006523�12407762022�016204� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * gl_warp_sin.h * Copyright (C) 1996-1997 Id Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT 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. */ 0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677, 1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916, 3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998, 4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632, 5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068, 6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368, 7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562, 7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759, 8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222, 7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394, 7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883, 6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398, 5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647, 4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193, 3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281, 1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633, 9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677, -1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916, -3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998, -4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632, -5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068, -6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368, -7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562, -7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759, -8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222, -7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394, -7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883, -6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398, -5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647, -4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193, -3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281, -1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633, �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_vorbis.h����������������������������������������������������������������0000644�0000000�0000000�00000000341�12113434521�016032� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Ogg/Vorbis streaming music support. */ #if !defined(_SND_VORBIS_H_) #define _SND_VORBIS_H_ 1 #if defined(USE_CODEC_VORBIS) extern snd_codec_t vorbis_codec; #endif /* USE_CODEC_VORBIS */ #endif /* ! _SND_VORBIS_H_ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cvar.c����������������������������������������������������������������������0000644�0000000�0000000�00000030404�12407762022�014621� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cvar.c -- dynamic variable tracking #include "quakedef.h" static cvar_t *cvar_vars; static char cvar_null_string[] = ""; //============================================================================== // // USER COMMANDS // //============================================================================== void Cvar_Reset (const char *name); //johnfitz /* ============ Cvar_List_f -- johnfitz ============ */ void Cvar_List_f (void) { cvar_t *cvar; const char *partial; int len, count; if (Cmd_Argc() > 1) { partial = Cmd_Argv (1); len = Q_strlen(partial); } else { partial = NULL; len = 0; } count = 0; for (cvar = cvar_vars ; cvar ; cvar = cvar->next) { if (partial && Q_strncmp(partial, cvar->name, len)) { continue; } Con_SafePrintf ("%s%s %s \"%s\"\n", (cvar->flags & CVAR_ARCHIVE) ? "*" : " ", (cvar->flags & CVAR_NOTIFY) ? "s" : " ", cvar->name, cvar->string); count++; } Con_SafePrintf ("%i cvars", count); if (partial) { Con_SafePrintf (" beginning with \"%s\"", partial); } Con_SafePrintf ("\n"); } /* ============ Cvar_Inc_f -- johnfitz ============ */ void Cvar_Inc_f (void) { switch (Cmd_Argc()) { default: case 1: Con_Printf("inc <cvar> [amount] : increment cvar\n"); break; case 2: Cvar_SetValue (Cmd_Argv(1), Cvar_VariableValue(Cmd_Argv(1)) + 1); break; case 3: Cvar_SetValue (Cmd_Argv(1), Cvar_VariableValue(Cmd_Argv(1)) + Q_atof(Cmd_Argv(2))); break; } } /* ============ Cvar_Toggle_f -- johnfitz ============ */ void Cvar_Toggle_f (void) { switch (Cmd_Argc()) { default: case 1: Con_Printf("toggle <cvar> : toggle cvar\n"); break; case 2: if (Cvar_VariableValue(Cmd_Argv(1))) Cvar_Set (Cmd_Argv(1), "0"); else Cvar_Set (Cmd_Argv(1), "1"); break; } } /* ============ Cvar_Cycle_f -- johnfitz ============ */ void Cvar_Cycle_f (void) { int i; if (Cmd_Argc() < 3) { Con_Printf("cycle <cvar> <value list>: cycle cvar through a list of values\n"); return; } //loop through the args until you find one that matches the current cvar value. //yes, this will get stuck on a list that contains the same value twice. //it's not worth dealing with, and i'm not even sure it can be dealt with. for (i = 2; i < Cmd_Argc(); i++) { //zero is assumed to be a string, even though it could actually be zero. The worst case //is that the first time you call this command, it won't match on zero when it should, but after that, //it will be comparing strings that all had the same source (the user) so it will work. if (Q_atof(Cmd_Argv(i)) == 0) { if (!strcmp(Cmd_Argv(i), Cvar_VariableString(Cmd_Argv(1)))) break; } else { if (Q_atof(Cmd_Argv(i)) == Cvar_VariableValue(Cmd_Argv(1))) break; } } if (i == Cmd_Argc()) Cvar_Set (Cmd_Argv(1), Cmd_Argv(2)); // no match else if (i + 1 == Cmd_Argc()) Cvar_Set (Cmd_Argv(1), Cmd_Argv(2)); // matched last value in list else Cvar_Set (Cmd_Argv(1), Cmd_Argv(i+1)); // matched earlier in list } /* ============ Cvar_Reset_f -- johnfitz ============ */ void Cvar_Reset_f (void) { switch (Cmd_Argc()) { default: case 1: Con_Printf ("reset <cvar> : reset cvar to default\n"); break; case 2: Cvar_Reset (Cmd_Argv(1)); break; } } /* ============ Cvar_ResetAll_f -- johnfitz ============ */ void Cvar_ResetAll_f (void) { cvar_t *var; for (var = cvar_vars ; var ; var = var->next) Cvar_Reset (var->name); } /* ============ Cvar_ResetCfg_f -- QuakeSpasm ============ */ void Cvar_ResetCfg_f (void) { cvar_t *var; for (var = cvar_vars ; var ; var = var->next) if (var->flags & CVAR_ARCHIVE) Cvar_Reset (var->name); } //============================================================================== // // INIT // //============================================================================== /* ============ Cvar_Init -- johnfitz ============ */ void Cvar_Init (void) { Cmd_AddCommand ("cvarlist", Cvar_List_f); Cmd_AddCommand ("toggle", Cvar_Toggle_f); Cmd_AddCommand ("cycle", Cvar_Cycle_f); Cmd_AddCommand ("inc", Cvar_Inc_f); Cmd_AddCommand ("reset", Cvar_Reset_f); Cmd_AddCommand ("resetall", Cvar_ResetAll_f); Cmd_AddCommand ("resetcfg", Cvar_ResetCfg_f); } //============================================================================== // // CVAR FUNCTIONS // //============================================================================== /* ============ Cvar_FindVar ============ */ cvar_t *Cvar_FindVar (const char *var_name) { cvar_t *var; for (var = cvar_vars ; var ; var = var->next) { if (!Q_strcmp(var_name, var->name)) return var; } return NULL; } cvar_t *Cvar_FindVarAfter (const char *prev_name, unsigned int with_flags) { cvar_t *var; if (*prev_name) { var = Cvar_FindVar (prev_name); if (!var) return NULL; var = var->next; } else var = cvar_vars; // search for the next cvar matching the needed flags while (var) { if ((var->flags & with_flags) || !with_flags) break; var = var->next; } return var; } /* ============ Cvar_LockVar ============ */ void Cvar_LockVar (const char *var_name) { cvar_t *var = Cvar_FindVar (var_name); if (var) var->flags |= CVAR_LOCKED; } void Cvar_UnlockVar (const char *var_name) { cvar_t *var = Cvar_FindVar (var_name); if (var) var->flags &= ~CVAR_LOCKED; } void Cvar_UnlockAll (void) { cvar_t *var; for (var = cvar_vars ; var ; var = var->next) { var->flags &= ~CVAR_LOCKED; } } /* ============ Cvar_VariableValue ============ */ float Cvar_VariableValue (const char *var_name) { cvar_t *var; var = Cvar_FindVar (var_name); if (!var) return 0; return Q_atof (var->string); } /* ============ Cvar_VariableString ============ */ const char *Cvar_VariableString (const char *var_name) { cvar_t *var; var = Cvar_FindVar (var_name); if (!var) return cvar_null_string; return var->string; } /* ============ Cvar_CompleteVariable ============ */ const char *Cvar_CompleteVariable (const char *partial) { cvar_t *cvar; int len; len = Q_strlen(partial); if (!len) return NULL; // check functions for (cvar = cvar_vars ; cvar ; cvar = cvar->next) { if (!Q_strncmp(partial, cvar->name, len)) return cvar->name; } return NULL; } /* ============ Cvar_Reset -- johnfitz ============ */ void Cvar_Reset (const char *name) { cvar_t *var; var = Cvar_FindVar (name); if (!var) Con_Printf ("variable \"%s\" not found\n", name); else Cvar_SetQuick (var, var->default_string); } void Cvar_SetQuick (cvar_t *var, const char *value) { if (var->flags & (CVAR_ROM|CVAR_LOCKED)) return; if (!(var->flags & CVAR_REGISTERED)) return; if (!var->string) var->string = Z_Strdup (value); else { int len; if (!strcmp(var->string, value)) return; // no change var->flags |= CVAR_CHANGED; len = Q_strlen (value); if (len != Q_strlen(var->string)) { Z_Free ((void *)var->string); var->string = (char *) Z_Malloc (len + 1); } memcpy ((char *)var->string, value, len + 1); } var->value = Q_atof (var->string); //johnfitz -- save initial value for "reset" command if (!var->default_string) var->default_string = Z_Strdup (var->string); //johnfitz -- during initialization, update default too else if (!host_initialized) { // Sys_Printf("changing default of %s: %s -> %s\n", // var->name, var->default_string, var->string); Z_Free ((void *)var->default_string); var->default_string = Z_Strdup (var->string); } //johnfitz if (var->callback) var->callback (var); } void Cvar_SetValueQuick (cvar_t *var, const float value) { char val[32], *ptr = val; if (value == (float)((int)value)) q_snprintf (val, sizeof(val), "%i", (int)value); else { q_snprintf (val, sizeof(val), "%f", value); // kill trailing zeroes while (*ptr) ptr++; while (--ptr > val && *ptr == '0' && ptr[-1] != '.') *ptr = '\0'; } Cvar_SetQuick (var, val); } /* ============ Cvar_Set ============ */ void Cvar_Set (const char *var_name, const char *value) { cvar_t *var; var = Cvar_FindVar (var_name); if (!var) { // there is an error in C code if this happens Con_Printf ("Cvar_Set: variable %s not found\n", var_name); return; } Cvar_SetQuick (var, value); } /* ============ Cvar_SetValue ============ */ void Cvar_SetValue (const char *var_name, const float value) { char val[32], *ptr = val; if (value == (float)((int)value)) q_snprintf (val, sizeof(val), "%i", (int)value); else { q_snprintf (val, sizeof(val), "%f", value); // kill trailing zeroes while (*ptr) ptr++; while (--ptr > val && *ptr == '0' && ptr[-1] != '.') *ptr = '\0'; } Cvar_Set (var_name, val); } /* ============ Cvar_SetROM ============ */ void Cvar_SetROM (const char *var_name, const char *value) { cvar_t *var = Cvar_FindVar (var_name); if (var) { var->flags &= ~CVAR_ROM; Cvar_SetQuick (var, value); var->flags |= CVAR_ROM; } } /* ============ Cvar_SetValueROM ============ */ void Cvar_SetValueROM (const char *var_name, const float value) { cvar_t *var = Cvar_FindVar (var_name); if (var) { var->flags &= ~CVAR_ROM; Cvar_SetValueQuick (var, value); var->flags |= CVAR_ROM; } } /* ============ Cvar_RegisterVariable Adds a freestanding variable to the variable list. ============ */ void Cvar_RegisterVariable (cvar_t *variable) { char value[512]; qboolean set_rom; cvar_t *cursor,*prev; //johnfitz -- sorted list insert // first check to see if it has already been defined if (Cvar_FindVar (variable->name)) { Con_Printf ("Can't register variable %s, already defined\n", variable->name); return; } // check for overlap with a command if (Cmd_Exists (variable->name)) { Con_Printf ("Cvar_RegisterVariable: %s is a command\n", variable->name); return; } // link the variable in //johnfitz -- insert each entry in alphabetical order if (cvar_vars == NULL || strcmp(variable->name, cvar_vars->name) < 0) // insert at front { variable->next = cvar_vars; cvar_vars = variable; } else //insert later { prev = cvar_vars; cursor = cvar_vars->next; while (cursor && (strcmp(variable->name, cursor->name) > 0)) { prev = cursor; cursor = cursor->next; } variable->next = prev->next; prev->next = variable; } //johnfitz variable->flags |= CVAR_REGISTERED; // copy the value off, because future sets will Z_Free it q_strlcpy (value, variable->string, sizeof(value)); variable->string = NULL; variable->default_string = NULL; if (!(variable->flags & CVAR_CALLBACK)) variable->callback = NULL; // set it through the function to be consistent set_rom = (variable->flags & CVAR_ROM); variable->flags &= ~CVAR_ROM; Cvar_SetQuick (variable, value); if (set_rom) variable->flags |= CVAR_ROM; } /* ============ Cvar_SetCallback Set a callback function to the var ============ */ void Cvar_SetCallback (cvar_t *var, cvarcallback_t func) { var->callback = func; if (func) var->flags |= CVAR_CALLBACK; else var->flags &= ~CVAR_CALLBACK; } /* ============ Cvar_Command Handles variable inspection and changing from the console ============ */ qboolean Cvar_Command (void) { cvar_t *v; // check variables v = Cvar_FindVar (Cmd_Argv(0)); if (!v) return false; // perform a variable print or set if (Cmd_Argc() == 1) { Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string); return true; } Cvar_Set (v->name, Cmd_Argv(1)); return true; } /* ============ Cvar_WriteVariables Writes lines containing "set variable value" for all variables with the archive flag set to true. ============ */ void Cvar_WriteVariables (FILE *f) { cvar_t *var; for (var = cvar_vars ; var ; var = var->next) { if (var->flags & CVAR_ARCHIVE) fprintf (f, "%s \"%s\"\n", var->name, var->string); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_wins.c������������������������������������������������������������������0000644�0000000�0000000�00000031604�12407762022�015517� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "q_stdinc.h" #include "arch_def.h" #include "net_sys.h" #include "quakedef.h" #include "net_defs.h" static sys_socket_t net_acceptsocket = INVALID_SOCKET; // socket for fielding new connections static sys_socket_t net_controlsocket; static sys_socket_t net_broadcastsocket = 0; static struct sockaddr_in broadcastaddr; static in_addr_t myAddr; #include "net_wins.h" int winsock_initialized = 0; WSADATA winsockdata; #define __wsaerr_static /* not static: used by net_wipx.c too */ #include "wsaerror.h" //============================================================================= static double blocktime; static INT_PTR PASCAL FAR BlockingHook (void) { MSG msg; BOOL ret; if ((Sys_DoubleTime() - blocktime) > 2.0) { WSACancelBlockingCall(); return FALSE; } /* get the next message, if any */ ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); /* if we got one, process it */ if (ret) { TranslateMessage(&msg); DispatchMessage(&msg); } /* TRUE if we got a message */ return ret; } static void WINS_GetLocalAddress (void) { struct hostent *local = NULL; char buff[MAXHOSTNAMELEN]; in_addr_t addr; int err; if (myAddr != INADDR_ANY) return; if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR) { err = SOCKETERRNO; Con_SafePrintf("WINS_GetLocalAddress: gethostname failed (%s)\n", socketerror(err)); return; } buff[MAXHOSTNAMELEN - 1] = 0; blocktime = Sys_DoubleTime(); WSASetBlockingHook(BlockingHook); local = gethostbyname(buff); err = WSAGetLastError(); WSAUnhookBlockingHook(); if (local == NULL) { Con_SafePrintf("WINS_GetLocalAddress: gethostbyname failed (%s)\n", __WSAE_StrError(err)); return; } myAddr = *(in_addr_t *)local->h_addr_list[0]; addr = ntohl(myAddr); sprintf(my_tcpip_address, "%ld.%ld.%ld.%ld", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); } sys_socket_t WINS_Init (void) { int i, err; char buff[MAXHOSTNAMELEN]; if (COM_CheckParm ("-noudp")) return -1; if (winsock_initialized == 0) { err = WSAStartup(MAKEWORD(1,1), &winsockdata); if (err != 0) { Con_SafePrintf("Winsock initialization failed (%s)\n", socketerror(err)); return INVALID_SOCKET; } } winsock_initialized++; // determine my name & address if (gethostname(buff, MAXHOSTNAMELEN) != 0) { err = SOCKETERRNO; Con_SafePrintf("WINS_Init: gethostname failed (%s)\n", socketerror(err)); } else { buff[MAXHOSTNAMELEN - 1] = 0; } i = COM_CheckParm ("-ip"); if (i) { if (i < com_argc-1) { myAddr = inet_addr(com_argv[i+1]); if (myAddr == INADDR_NONE) Sys_Error ("%s is not a valid IP address", com_argv[i+1]); strcpy(my_tcpip_address, com_argv[i+1]); } else { Sys_Error ("NET_Init: you must specify an IP address after -ip"); } } else { myAddr = INADDR_ANY; strcpy(my_tcpip_address, "INADDR_ANY"); } if ((net_controlsocket = WINS_OpenSocket(0)) == INVALID_SOCKET) { Con_SafePrintf("WINS_Init: Unable to open control socket, UDP disabled\n"); if (--winsock_initialized == 0) WSACleanup (); return INVALID_SOCKET; } broadcastaddr.sin_family = AF_INET; broadcastaddr.sin_addr.s_addr = INADDR_BROADCAST; broadcastaddr.sin_port = htons((unsigned short)net_hostport); Con_SafePrintf("UDP Initialized\n"); tcpipAvailable = true; return net_controlsocket; } //============================================================================= void WINS_Shutdown (void) { WINS_Listen (false); WINS_CloseSocket (net_controlsocket); if (--winsock_initialized == 0) WSACleanup (); } //============================================================================= void WINS_Listen (qboolean state) { // enable listening if (state) { if (net_acceptsocket != INVALID_SOCKET) return; WINS_GetLocalAddress(); if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == INVALID_SOCKET) Sys_Error ("WINS_Listen: Unable to open accept socket"); return; } // disable listening if (net_acceptsocket == INVALID_SOCKET) return; WINS_CloseSocket (net_acceptsocket); net_acceptsocket = INVALID_SOCKET; } //============================================================================= sys_socket_t WINS_OpenSocket (int port) { sys_socket_t newsocket; struct sockaddr_in address; u_long _true = 1; int err; if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { err = SOCKETERRNO; Con_SafePrintf("WINS_OpenSocket: %s\n", socketerror(err)); return INVALID_SOCKET; } if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR) goto ErrorReturn; memset(&address, 0, sizeof(struct sockaddr_in)); address.sin_family = AF_INET; address.sin_addr.s_addr = myAddr; address.sin_port = htons((unsigned short)port); if (bind (newsocket, (struct sockaddr *)&address, sizeof(address)) == 0) return newsocket; if (tcpipAvailable) { err = SOCKETERRNO; Sys_Error ("Unable to bind to %s (%s)", WINS_AddrToString ((struct qsockaddr *) &address), socketerror(err)); return INVALID_SOCKET; /* not reached */ } /* else: we are still in init phase, no need to error */ ErrorReturn: err = SOCKETERRNO; Con_SafePrintf("WINS_OpenSocket: %s\n", socketerror(err)); closesocket (newsocket); return INVALID_SOCKET; } //============================================================================= int WINS_CloseSocket (sys_socket_t socketid) { if (socketid == net_broadcastsocket) net_broadcastsocket = 0; return closesocket (socketid); } //============================================================================= /* ============ PartialIPAddress this lets you type only as much of the net address as required, using the local network components to fill in the rest ============ */ static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr) { char buff[256]; char *b; int addr, mask, num, port, run; buff[0] = '.'; b = buff; strcpy(buff+1, in); if (buff[1] == '.') b++; addr = 0; mask = -1; while (*b == '.') { b++; num = 0; run = 0; while (!( *b < '0' || *b > '9')) { num = num*10 + *b++ - '0'; if (++run > 3) return -1; } if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0) return -1; if (num < 0 || num > 255) return -1; mask <<= 8; addr = (addr<<8) + num; } if (*b++ == ':') port = Q_atoi(b); else port = net_hostport; hostaddr->qsa_family = AF_INET; ((struct sockaddr_in *)hostaddr)->sin_port = htons((unsigned short)port); ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); return 0; } //============================================================================= int WINS_Connect (sys_socket_t socketid, struct qsockaddr *addr) { return 0; } //============================================================================= sys_socket_t WINS_CheckNewConnections (void) { char buf[4096]; if (net_acceptsocket == INVALID_SOCKET) return INVALID_SOCKET; if (recvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) != SOCKET_ERROR) { return net_acceptsocket; } return INVALID_SOCKET; } //============================================================================= int WINS_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr) { socklen_t addrlen = sizeof(struct qsockaddr); int ret; ret = recvfrom (socketid, (char *)buf, len, 0, (struct sockaddr *)addr, &addrlen); if (ret == SOCKET_ERROR) { int err = SOCKETERRNO; if (err == NET_EWOULDBLOCK || err == NET_ECONNREFUSED) return 0; Con_SafePrintf ("WINS_Read, recvfrom: %s\n", socketerror(err)); } return ret; } //============================================================================= static int WINS_MakeSocketBroadcastCapable (sys_socket_t socketid) { int i = 1; // make this socket broadcast capable if (setsockopt(socketid, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == SOCKET_ERROR) { int err = SOCKETERRNO; Con_SafePrintf ("UDP, setsockopt: %s\n", socketerror(err)); return -1; } net_broadcastsocket = socketid; return 0; } //============================================================================= int WINS_Broadcast (sys_socket_t socketid, byte *buf, int len) { int ret; if (socketid != net_broadcastsocket) { if (net_broadcastsocket != 0) Sys_Error("Attempted to use multiple broadcasts sockets"); WINS_GetLocalAddress(); ret = WINS_MakeSocketBroadcastCapable (socketid); if (ret == -1) { Con_Printf("Unable to make socket broadcast capable\n"); return ret; } } return WINS_Write (socketid, buf, len, (struct qsockaddr *)&broadcastaddr); } //============================================================================= int WINS_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr) { int ret; ret = sendto (socketid, (char *)buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); if (ret == SOCKET_ERROR) { int err = SOCKETERRNO; if (err == NET_EWOULDBLOCK) return 0; Con_SafePrintf ("WINS_Write, sendto: %s\n", socketerror(err)); } return ret; } //============================================================================= const char *WINS_AddrToString (struct qsockaddr *addr) { static char buffer[22]; int haddr; haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); return buffer; } //============================================================================= int WINS_StringToAddr (const char *string, struct qsockaddr *addr) { int ha1, ha2, ha3, ha4, hp, ipaddr; sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; addr->qsa_family = AF_INET; ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp); return 0; } //============================================================================= int WINS_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr) { socklen_t addrlen = sizeof(struct qsockaddr); in_addr_t a; memset(addr, 0, sizeof(struct qsockaddr)); getsockname(socketid, (struct sockaddr *)addr, &addrlen); a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; if (a == 0 || a == htonl(INADDR_LOOPBACK)) ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; return 0; } //============================================================================= int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name) { struct hostent *hostentry; hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); if (hostentry) { Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); return 0; } Q_strcpy (name, WINS_AddrToString (addr)); return 0; } //============================================================================= int WINS_GetAddrFromName (const char *name, struct qsockaddr *addr) { struct hostent *hostentry; if (name[0] >= '0' && name[0] <= '9') return PartialIPAddress (name, addr); hostentry = gethostbyname (name); if (!hostentry) return -1; addr->qsa_family = AF_INET; ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport); ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(in_addr_t *)hostentry->h_addr_list[0]; return 0; } //============================================================================= int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) { if (addr1->qsa_family != addr2->qsa_family) return -1; if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) return -1; if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) return 1; return 0; } //============================================================================= int WINS_GetSocketPort (struct qsockaddr *addr) { return ntohs(((struct sockaddr_in *)addr)->sin_port); } int WINS_SetSocketPort (struct qsockaddr *addr, int port) { ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port); return 0; } //============================================================================= ����������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cd_sdl.c��������������������������������������������������������������������0000644�0000000�0000000�00000030175�12420513075�015120� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * cd_sdl.c * * Copyright (C) 1996-1997 Id Software, Inc. * Taken from the Twilight project with modifications * to make it work with Hexen II: Hammer of Thyrion. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif #ifndef SDL_INIT_CDROM /* SDL dropped support for cd audio since v1.3.0 */ #pragma message("Warning: SDL CDAudio support disabled") #include "cd_null.c" #else /* SDL_INIT_CDROM */ #include "quakedef.h" static qboolean cdValid = false; static qboolean playing = false; static qboolean wasPlaying = false; static qboolean enabled = true; static qboolean playLooping = false; static byte remap[100]; static byte playTrack; static double endOfTrack = -1.0, pausetime = -1.0; static SDL_CD *cd_handle; static int cd_dev = -1; static float old_cdvolume; static qboolean hw_vol_works = true; static void CDAudio_Eject(void) { if (!cd_handle || !enabled) return; #ifdef __linux__ SDL_CDStop(cd_handle); /* see CDAudio_Stop() */ #endif if (SDL_CDEject(cd_handle) == -1) Con_Printf ("Unable to eject CD-ROM: %s\n", SDL_GetError ()); } static int CDAudio_GetAudioDiskInfo(void) { cdValid = false; if (!cd_handle) return -1; if ( ! CD_INDRIVE(SDL_CDStatus(cd_handle)) ) return -1; cdValid = true; return 0; } int CDAudio_Play(byte track, qboolean looping) { int len_m, len_s, len_f; if (!cd_handle || !enabled) return -1; if (!cdValid) { CDAudio_GetAudioDiskInfo(); if (!cdValid) return -1; } track = remap[track]; if (track < 1 || track > cd_handle->numtracks) { Con_Printf ("CDAudio_Play: Bad track number %d.\n", track); return -1; } if (cd_handle->track[track-1].type == SDL_DATA_TRACK) { Con_Printf ("CDAudio_Play: track %d is not audio\n", track); return -1; } if (playing) { if (playTrack == track) return 0; CDAudio_Stop(); } if (SDL_CDPlay(cd_handle, cd_handle->track[track-1].offset, cd_handle->track[track-1].length) == -1) { Con_Printf ("CDAudio_Play: Unable to play track %d: %s\n", track, SDL_GetError ()); return -1; } playLooping = looping; playTrack = track; playing = true; FRAMES_TO_MSF(cd_handle->track[track-1].length, &len_m, &len_s, &len_f); endOfTrack = realtime + ((double)len_m * 60.0) + (double)len_s + (double)len_f / (double)CD_FPS; /* Add the pregap for the next track. This means that disc-at-once CDs * won't loop smoothly, but they wouldn't anyway so it doesn't really * matter. SDL doesn't give us pregap information anyway, so you'll * just have to live with it. */ endOfTrack += 2.0; pausetime = -1.0; if (bgmvolume.value == 0) /* don't bother advancing */ CDAudio_Pause (); return 0; } void CDAudio_Stop(void) { if (!cd_handle || !enabled) return; if (!playing) return; #ifdef __linux__ /* Don't really stop, but just pause: On some devices, the CDROMSTOP * ioctl causes any followup ioctls to fail for a considerable time. * observed with a TSSTcorp CDW/DVD SH-M522C drive with TS05 and TS08 * firmware versions running under a 2.6.27.25 kernel, and with a * Samsung DVD r/w drive running under 2.6.35.6 kernel. * Therefore, avoid dead stops if playback may be resumed shortly. */ if (SDL_CDPause(cd_handle) == -1) Con_Printf ("CDAudio_Stop: Unable to stop CD-ROM (%s)\n", SDL_GetError()); #else if (SDL_CDStop(cd_handle) == -1) Con_Printf ("CDAudio_Stop: Unable to stop CD-ROM (%s)\n", SDL_GetError()); #endif wasPlaying = false; playing = false; pausetime = -1.0; endOfTrack = -1.0; } void CDAudio_Pause(void) { if (!cd_handle || !enabled) return; if (!playing) return; if (SDL_CDPause(cd_handle) == -1) Con_Printf ("Unable to pause CD-ROM: %s\n", SDL_GetError()); wasPlaying = playing; playing = false; pausetime = realtime; } void CDAudio_Resume(void) { if (!cd_handle || !enabled) return; if (!cdValid) return; if (!wasPlaying) return; if (SDL_CDResume(cd_handle) == -1) Con_Printf ("Unable to resume CD-ROM: %s\n", SDL_GetError()); playing = true; endOfTrack += realtime - pausetime; pausetime = -1.0; } static int get_first_audiotrk (void) { int i; for (i = 0; i < cd_handle->numtracks; ++i) if (cd_handle->track[i].type != SDL_DATA_TRACK) return ++i; return 1; } static void CD_f (void) { const char *command; int ret, n; if (Cmd_Argc() < 2) { Con_Printf("commands:"); Con_Printf("on, off, reset, remap, \n"); Con_Printf("play, stop, loop, pause, resume\n"); Con_Printf("eject, info, next, prev\n"); return; } command = Cmd_Argv (1); if (q_strcasecmp(command, "on") == 0) { enabled = true; return; } if (q_strcasecmp(command, "off") == 0) { if (playing) CDAudio_Stop(); enabled = false; return; } if (q_strcasecmp(command, "reset") == 0) { enabled = true; if (playing) CDAudio_Stop(); for (n = 0; n < 100; n++) remap[n] = n; CDAudio_GetAudioDiskInfo(); return; } if (q_strcasecmp(command, "remap") == 0) { ret = Cmd_Argc() - 2; if (ret <= 0) { for (n = 1; n < 100; n++) if (remap[n] != n) Con_Printf(" %u -> %u\n", n, remap[n]); return; } for (n = 1; n <= ret; n++) remap[n] = atoi(Cmd_Argv (n + 1)); return; } if (!cdValid) { CDAudio_GetAudioDiskInfo(); if (!cdValid) { Con_Printf("No CD in player.\n"); return; } } if (q_strcasecmp(command, "play") == 0) { n = atoi(Cmd_Argv (2)); if (n == 0) n = 1; CDAudio_Play((byte)n, false); return; } if (q_strcasecmp(command, "loop") == 0) { CDAudio_Play((byte)atoi(Cmd_Argv (2)), true); return; } if (q_strcasecmp(command, "stop") == 0) { CDAudio_Stop(); return; } if (q_strcasecmp(command, "pause") == 0) { CDAudio_Pause(); return; } if (q_strcasecmp(command, "resume") == 0) { CDAudio_Resume(); return; } if (q_strcasecmp(command, "eject") == 0) { if (playing) CDAudio_Stop(); CDAudio_Eject(); cdValid = false; return; } if (q_strcasecmp(command, "info") == 0) { int current_min, current_sec, current_frame; int length_min, length_sec, length_frame; Con_Printf ("%u tracks\n", cd_handle->numtracks); if (playing) Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack); else if (wasPlaying) Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack); if (playing || wasPlaying) { SDL_CDStatus(cd_handle); FRAMES_TO_MSF(cd_handle->cur_frame, ¤t_min, ¤t_sec, ¤t_frame); FRAMES_TO_MSF(cd_handle->track[playTrack-1].length, &length_min, &length_sec, &length_frame); Con_Printf ("Current position: %d:%02d.%02d (of %d:%02d.%02d)\n", current_min, current_sec, current_frame * 60 / CD_FPS, length_min, length_sec, length_frame * 60 / CD_FPS); } Con_Printf("Volume is %f\n", bgmvolume.value); return; } if (q_strcasecmp(command, "next") == 0) { if (playTrack == cd_handle->numtracks) playTrack = get_first_audiotrk() - 1; CDAudio_Play(playTrack + 1, playLooping); return; } if (q_strcasecmp(command, "prev") == 0) { if (playTrack == get_first_audiotrk()) playTrack = cd_handle->numtracks + 1; CDAudio_Play(playTrack - 1, playLooping); return; } Con_Printf ("cd: unknown command \"%s\"\n", command); } static qboolean CD_GetVolume (void *unused) { /* FIXME: write proper code in here when SDL supports cdrom volume control some day. */ return false; } static qboolean CD_SetVolume (void *unused) { /* FIXME: write proper code in here when SDL supports cdrom volume control some day. */ return false; } static qboolean CDAudio_SetVolume (float value) { if (!cd_handle || !enabled) return false; old_cdvolume = value; if (value == 0.0f) CDAudio_Pause (); else CDAudio_Resume(); if (!hw_vol_works) { return false; } else { /* FIXME: write proper code in here when SDL supports cdrom volume control some day. */ return CD_SetVolume (NULL); } } void CDAudio_Update(void) { CDstatus curstat; /* static double lastchk;*/ if (!cd_handle || !enabled) return; if (old_cdvolume != bgmvolume.value) CDAudio_SetVolume (bgmvolume.value); /* if (playing && realtime > lastchk)*/ if (playing && realtime > endOfTrack) { /* lastchk = realtime + 2;*/ /* two seconds between chks */ curstat = SDL_CDStatus(cd_handle); if (curstat != CD_PLAYING && curstat != CD_PAUSED) { playing = false; endOfTrack = -1.0; if (playLooping) CDAudio_Play(playTrack, true); } } } static const char *get_cddev_arg (const char *arg) { #if defined(_WIN32) /* arg should be like "D:\", make sure it is so, * but tolerate args like "D" or "D:", as well. */ static char drive[4]; if (!arg || ! *arg) return NULL; if (arg[1] != '\0') { if (arg[1] != ':') return NULL; if (arg[2] != '\0') { if (arg[2] != '\\' && arg[2] != '/') return NULL; if (arg[3] != '\0') return NULL; } } if (*arg >= 'A' && *arg <= 'Z') { drive[0] = *arg; drive[1] = ':'; drive[2] = '\\'; drive[3] = '\0'; return drive; } else if (*arg >= 'a' && *arg <= 'z') { /* make it uppercase for SDL */ drive[0] = *arg - ('a' - 'A'); drive[1] = ':'; drive[2] = '\\'; drive[3] = '\0'; return drive; } return NULL; #else if (!arg || ! *arg) return NULL; return arg; #endif } static void export_cddev_arg (void) { /* Bad ugly hack to workaround SDL's cdrom device detection. * not needed for windows due to the way SDL_cdrom works. */ #if !defined(_WIN32) int i = COM_CheckParm("-cddev"); if (i != 0 && i < com_argc - 1 && com_argv[i+1][0] != '\0') { static char arg[64]; q_snprintf(arg, sizeof(arg), "SDL_CDROM=%s", com_argv[i+1]); putenv(arg); } #endif } int CDAudio_Init(void) { int i, sdl_num_drives; if (safemode || COM_CheckParm("-nocdaudio")) return -1; export_cddev_arg(); if (SDL_InitSubSystem(SDL_INIT_CDROM) < 0) { Con_Printf("Couldn't init SDL cdrom: %s\n", SDL_GetError()); return -1; } sdl_num_drives = SDL_CDNumDrives (); Con_Printf ("SDL detected %d CD-ROM drive%c\n", sdl_num_drives, sdl_num_drives == 1 ? ' ' : 's'); if (sdl_num_drives < 1) return -1; if ((i = COM_CheckParm("-cddev")) != 0 && i < com_argc - 1) { const char *userdev = get_cddev_arg(com_argv[i+1]); if (!userdev) { Con_Printf("Invalid argument to -cddev\n"); return -1; } for (i = 0; i < sdl_num_drives; i++) { if (!q_strcasecmp(SDL_CDName(i), userdev)) { cd_dev = i; break; } } if (cd_dev == -1) { Con_Printf("SDL couldn't find cdrom device %s\n", userdev); return -1; } } if (cd_dev == -1) cd_dev = 0; /* default drive */ cd_handle = SDL_CDOpen(cd_dev); if (!cd_handle) { Con_Printf ("CDAudio_Init: Unable to open CD-ROM drive %s (%s)\n", SDL_CDName(cd_dev), SDL_GetError()); return -1; } for (i = 0; i < 100; i++) remap[i] = i; enabled = true; old_cdvolume = bgmvolume.value; Con_Printf("CDAudio initialized (SDL, using %s)\n", SDL_CDName(cd_dev)); if (CDAudio_GetAudioDiskInfo()) { Con_Printf("CDAudio_Init: No CD in drive\n"); cdValid = false; } Cmd_AddCommand ("cd", CD_f); hw_vol_works = CD_GetVolume (NULL); /* no SDL support at present. */ if (hw_vol_works) hw_vol_works = CDAudio_SetVolume (bgmvolume.value); return 0; } void CDAudio_Shutdown(void) { if (!cd_handle) return; CDAudio_Stop(); if (hw_vol_works) CD_SetVolume (NULL); /* no SDL support at present. */ #ifdef __linux__ SDL_CDStop(cd_handle); /* see CDAudio_Stop() */ #endif SDL_CDClose(cd_handle); cd_handle = NULL; cd_dev = -1; SDL_QuitSubSystem(SDL_INIT_CDROM); } #endif /* SDL_INIT_CDROM */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/wsaerror.h������������������������������������������������������������������0000644�0000000�0000000�00000011526�11407642431�015543� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� /* strings for winsock error codes. * from online references, such as * http://aluigi.org/mytoolz/winerr.h * http://www.winsock-error.com or * http://www.sockets.com/err_lst1.htm */ #ifndef __wsaerr_static #define __wsaerr_static static #endif /* static */ __wsaerr_static const char *__WSAE_StrError (int err) { switch (err) { case 0: return "No error"; case WSAEINTR: return "Interrupted system call"; /* 10004 */ case WSAEBADF: return "Bad file number"; /* 10009 */ case WSAEACCES: return "Permission denied"; /* 10013 */ case WSAEFAULT: return "Bad address"; /* 10014 */ case WSAEINVAL: return "Invalid argument (not bind)"; /* 10022 */ case WSAEMFILE: return "Too many open files"; /* 10024 */ case WSAEWOULDBLOCK: return "Operation would block"; /* 10035 */ case WSAEINPROGRESS: return "Operation now in progress"; /* 10036 */ case WSAEALREADY: return "Operation already in progress"; /* 10037 */ case WSAENOTSOCK: return "Socket operation on non-socket"; /* 10038 */ case WSAEDESTADDRREQ: return "Destination address required"; /* 10039 */ case WSAEMSGSIZE: return "Message too long"; /* 10040 */ case WSAEPROTOTYPE: return "Protocol wrong type for socket"; /* 10041 */ case WSAENOPROTOOPT: return "Bad protocol option"; /* 10042 */ case WSAEPROTONOSUPPORT: return "Protocol not supported"; /* 10043 */ case WSAESOCKTNOSUPPORT: return "Socket type not supported"; /* 10044 */ case WSAEOPNOTSUPP: return "Operation not supported on socket"; /* 10045 */ case WSAEPFNOSUPPORT: return "Protocol family not supported"; /* 10046 */ case WSAEAFNOSUPPORT: return "Address family not supported by protocol family"; /* 10047 */ case WSAEADDRINUSE: return "Address already in use"; /* 10048 */ case WSAEADDRNOTAVAIL: return "Can't assign requested address"; /* 10049 */ case WSAENETDOWN: return "Network is down"; /* 10050 */ case WSAENETUNREACH: return "Network is unreachable"; /* 10051 */ case WSAENETRESET: return "Net dropped connection or reset"; /* 10052 */ case WSAECONNABORTED: return "Software caused connection abort"; /* 10053 */ case WSAECONNRESET: return "Connection reset by peer"; /* 10054 */ case WSAENOBUFS: return "No buffer space available"; /* 10055 */ case WSAEISCONN: return "Socket is already connected"; /* 10056 */ case WSAENOTCONN: return "Socket is not connected"; /* 10057 */ case WSAESHUTDOWN: return "Can't send after socket shutdown"; /* 10058 */ case WSAETOOMANYREFS: return "Too many references, can't splice"; /* 10059 */ case WSAETIMEDOUT: return "Connection timed out"; /* 10060 */ case WSAECONNREFUSED: return "Connection refused"; /* 10061 */ case WSAELOOP: return "Too many levels of symbolic links"; /* 10062 */ case WSAENAMETOOLONG: return "File name too long"; /* 10063 */ case WSAEHOSTDOWN: return "Host is down"; /* 10064 */ case WSAEHOSTUNREACH: return "No Route to Host"; /* 10065 */ case WSAENOTEMPTY: return "Directory not empty"; /* 10066 */ case WSAEPROCLIM: return "Too many processes"; /* 10067 */ case WSAEUSERS: return "Too many users"; /* 10068 */ case WSAEDQUOT: return "Disc Quota Exceeded"; /* 10069 */ case WSAESTALE: return "Stale NFS file handle"; /* 10070 */ case WSAEREMOTE: return "Too many levels of remote in path"; /* 10071 */ case WSAEDISCON: return "Graceful shutdown in progress"; /* 10101 */ case WSASYSNOTREADY: return "Network SubSystem is unavailable"; /* 10091 */ case WSAVERNOTSUPPORTED: return "WINSOCK DLL Version out of range"; /* 10092 */ case WSANOTINITIALISED: return "Successful WSASTARTUP not yet performed"; /* 10093 */ case WSAHOST_NOT_FOUND: return "Authoritative answer: Host not found"; /* 11001 */ case WSATRY_AGAIN: return "Non-Authoritative: Host not found or SERVERFAIL"; /* 11002 */ case WSANO_RECOVERY: return "Non-Recoverable errors, FORMERR, REFUSED, NOTIMP"; /* 11003 */ case WSANO_DATA: return "Valid name, no data record of requested type"; /* 11004 */ case WSAENOMORE: return "10102: No more results"; /* 10102 */ case WSAECANCELLED: return "10103: Call has been canceled"; /* 10103 */ case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid"; /* 10104 */ case WSAEINVALIDPROVIDER: return "Service provider is invalid"; /* 10105 */ case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize"; /* 10106 */ case WSASYSCALLFAILURE: return "System call failure"; /* 10107 */ case WSASERVICE_NOT_FOUND: return "Service not found"; /* 10108 */ case WSATYPE_NOT_FOUND: return "Class type not found"; /* 10109 */ case WSA_E_NO_MORE: return "10110: No more results"; /* 10110 */ case WSA_E_CANCELLED: return "10111: Call was canceled"; /* 10111 */ case WSAEREFUSED: return "Database query was refused"; /* 10112 */ default: { static char _err_unknown[64]; sprintf(_err_unknown, "Unknown WSAE error (%d)", err); return _err_unknown; } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/client.h��������������������������������������������������������������������0000644�0000000�0000000�00000022256�12441376134�015162� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _CLIENT_H_ #define _CLIENT_H_ // client.h typedef struct { int length; char map[MAX_STYLESTRING]; char average; //johnfitz char peak; //johnfitz } lightstyle_t; typedef struct { char name[MAX_SCOREBOARDNAME]; float entertime; int frags; int colors; // two 4 bit fields byte translations[VID_GRADES*256]; } scoreboard_t; typedef struct { int destcolor[3]; int percent; // 0-256 } cshift_t; #define CSHIFT_CONTENTS 0 #define CSHIFT_DAMAGE 1 #define CSHIFT_BONUS 2 #define CSHIFT_POWERUP 3 #define NUM_CSHIFTS 4 #define NAME_LENGTH 64 // // client_state_t should hold all pieces of the client state // #define SIGNONS 4 // signon messages to receive before connected #define MAX_DLIGHTS 64 //johnfitz -- was 32 typedef struct { vec3_t origin; float radius; float die; // stop lighting after this time float decay; // drop this each second float minlight; // don't add when contributing less int key; vec3_t color; //johnfitz -- lit support via lordhavoc } dlight_t; #define MAX_BEAMS 32 //johnfitz -- was 24 typedef struct { int entity; struct qmodel_s *model; float endtime; vec3_t start, end; } beam_t; #define MAX_EFRAGS 4096 //ericw -- was 2048 //johnfitz -- was 640 #define MAX_MAPSTRING 2048 #define MAX_DEMOS 8 #define MAX_DEMONAME 16 typedef enum { ca_dedicated, // a dedicated server with no ability to start a client ca_disconnected, // full screen console with no connection ca_connected // valid netcon, talking to a server } cactive_t; // // the client_static_t structure is persistant through an arbitrary number // of server connections // typedef struct { cactive_t state; // personalization data sent to server char spawnparms[MAX_MAPSTRING]; // to restart a level // demo loop control int demonum; // -1 = don't play demos char demos[MAX_DEMOS][MAX_DEMONAME]; // when not playing // demo recording info must be here, because record is started before // entering a map (and clearing client_state_t) qboolean demorecording; qboolean demoplayback; // did the user pause demo playback? (separate from cl.paused because we don't // want a svc_setpause inside the demo to actually pause demo playback). qboolean demopaused; qboolean timedemo; int forcetrack; // -1 = use normal cd track FILE *demofile; int td_lastframe; // to meter out one message a frame int td_startframe; // host_framecount at start float td_starttime; // realtime at second frame of timedemo // connection information int signon; // 0 to SIGNONS struct qsocket_s *netcon; sizebuf_t message; // writing buffer to send to server } client_static_t; extern client_static_t cls; // // the client_state_t structure is wiped completely at every // server signon // typedef struct { int movemessages; // since connecting to this server // throw out the first couple, so the player // doesn't accidentally do something the // first frame usercmd_t cmd; // last command sent to the server // information for local display int stats[MAX_CL_STATS]; // health, etc int items; // inventory bit flags float item_gettime[32]; // cl.time of aquiring item, for blinking float faceanimtime; // use anim frame if cl.time < this cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types // the client maintains its own idea of view angles, which are // sent to the server each frame. The server sets punchangle when // the view is temporarliy offset, and an angle reset commands at the start // of each level and after teleporting. vec3_t mviewangles[2]; // during demo playback viewangles is lerped // between these vec3_t viewangles; vec3_t mvelocity[2]; // update by server, used for lean+bob // (0 is newest) vec3_t velocity; // lerped between mvelocity[0] and [1] vec3_t punchangle; // temporary offset // pitch drifting vars float idealpitch; float pitchvel; qboolean nodrift; float driftmove; double laststop; float viewheight; float crouch; // local amount for smoothing stepups qboolean paused; // send over by server qboolean onground; qboolean inwater; int intermission; // don't change view angle, full screen, etc int completed_time; // latched at intermission start double mtime[2]; // the timestamp of last two messages double time; // clients view of time, should be between // servertime and oldservertime to generate // a lerp point for other data double oldtime; // previous cl.time, time-oldtime is used // to decay light values and smooth step ups float last_received_message; // (realtime) for net trouble icon // // information that is static for the entire time connected to a server // struct qmodel_s *model_precache[MAX_MODELS]; struct sfx_s *sound_precache[MAX_SOUNDS]; char mapname[128]; char levelname[128]; // for display on solo scoreboard //johnfitz -- was 40. int viewentity; // cl_entitites[cl.viewentity] = player int maxclients; int gametype; // refresh related state struct qmodel_s *worldmodel; // cl_entitites[0].model struct efrag_s *free_efrags; int num_entities; // held in cl_entities array int num_statics; // held in cl_staticentities array entity_t viewent; // the gun model int cdtrack, looptrack; // cd audio // frag scoreboard scoreboard_t *scores; // [cl.maxclients] unsigned protocol; //johnfitz } client_state_t; // // cvars // extern cvar_t cl_name; extern cvar_t cl_color; extern cvar_t cl_upspeed; extern cvar_t cl_forwardspeed; extern cvar_t cl_backspeed; extern cvar_t cl_sidespeed; extern cvar_t cl_movespeedkey; extern cvar_t cl_yawspeed; extern cvar_t cl_pitchspeed; extern cvar_t cl_anglespeedkey; extern cvar_t cl_autofire; extern cvar_t cl_shownet; extern cvar_t cl_nolerp; extern cvar_t cfg_unbindall; extern cvar_t cl_pitchdriftspeed; extern cvar_t lookspring; extern cvar_t lookstrafe; extern cvar_t sensitivity; extern cvar_t m_pitch; extern cvar_t m_yaw; extern cvar_t m_forward; extern cvar_t m_side; #define MAX_TEMP_ENTITIES 256 //johnfitz -- was 64 #define MAX_STATIC_ENTITIES 512 //johnfitz -- was 128 #define MAX_VISEDICTS 4096 // larger, now we support BSP2 extern client_state_t cl; // FIXME, allocate dynamically extern efrag_t cl_efrags[MAX_EFRAGS]; extern entity_t cl_static_entities[MAX_STATIC_ENTITIES]; extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; extern dlight_t cl_dlights[MAX_DLIGHTS]; extern entity_t cl_temp_entities[MAX_TEMP_ENTITIES]; extern beam_t cl_beams[MAX_BEAMS]; extern entity_t *cl_visedicts[MAX_VISEDICTS]; extern int cl_numvisedicts; extern entity_t *cl_entities; //johnfitz -- was a static array, now on hunk extern int cl_max_edicts; //johnfitz -- only changes when new map loads //============================================================================= // // cl_main // dlight_t *CL_AllocDlight (int key); void CL_DecayLights (void); void CL_Init (void); void CL_EstablishConnection (const char *host); void CL_Signon1 (void); void CL_Signon2 (void); void CL_Signon3 (void); void CL_Signon4 (void); void CL_Disconnect (void); void CL_Disconnect_f (void); void CL_NextDemo (void); // // cl_input // typedef struct { int down[2]; // key nums holding it down int state; // low bit is down state } kbutton_t; extern kbutton_t in_mlook, in_klook; extern kbutton_t in_strafe; extern kbutton_t in_speed; void CL_InitInput (void); void CL_SendCmd (void); void CL_SendMove (const usercmd_t *cmd); int CL_ReadFromServer (void); void CL_BaseMove (usercmd_t *cmd); void CL_ParseTEnt (void); void CL_UpdateTEnts (void); void CL_ClearState (void); // // cl_demo.c // void CL_StopPlayback (void); int CL_GetMessage (void); void CL_Stop_f (void); void CL_Record_f (void); void CL_PlayDemo_f (void); void CL_TimeDemo_f (void); // // cl_parse.c // void CL_ParseServerMessage (void); void CL_NewTranslation (int slot); // // view // void V_StartPitchDrift (void); void V_StopPitchDrift (void); void V_RenderView (void); //void V_UpdatePalette (void); //johnfitz void V_Register (void); void V_ParseDamage (void); void V_SetContentsColor (int contents); // // cl_tent // void CL_InitTEnts (void); void CL_SignonReply (void); // // chase // extern cvar_t chase_active; void Chase_Init (void); void TraceLine (vec3_t start, vec3_t end, vec3_t impact); void Chase_UpdateForClient (void); //johnfitz void Chase_UpdateForDrawing (void); //johnfitz #endif /* _CLIENT_H_ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_dma.c�������������������������������������������������������������������0000644�0000000�0000000�00000054637�12636166045�015320� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2011 O. Sezer <sezero@users.sourceforge.net> Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // snd_dma.c -- main control for any streaming sound output device #include "quakedef.h" #include "snd_codec.h" #include "bgmusic.h" static void S_Play (void); static void S_PlayVol (void); static void S_SoundList (void); static void S_Update_ (void); void S_StopAllSounds (qboolean clear); static void S_StopAllSoundsC (void); // ======================================================================= // Internal sound data & structures // ======================================================================= channel_t snd_channels[MAX_CHANNELS]; int total_channels; static int snd_blocked = 0; static qboolean snd_initialized = false; static dma_t sn; volatile dma_t *shm = NULL; vec3_t listener_origin; vec3_t listener_forward; vec3_t listener_right; vec3_t listener_up; #define sound_nominal_clip_dist 1000.0 int soundtime; // sample PAIRS int paintedtime; // sample PAIRS int s_rawend; portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; #define MAX_SFX 1024 static sfx_t *known_sfx = NULL; // hunk allocated [MAX_SFX] static int num_sfx; static sfx_t *ambient_sfx[NUM_AMBIENTS]; static qboolean sound_started = false; cvar_t bgmvolume = {"bgmvolume", "1", CVAR_ARCHIVE}; cvar_t sfxvolume = {"volume", "0.7", CVAR_ARCHIVE}; cvar_t precache = {"precache", "1", CVAR_NONE}; cvar_t loadas8bit = {"loadas8bit", "0", CVAR_NONE}; cvar_t sndspeed = {"sndspeed", "11025", CVAR_NONE}; cvar_t snd_mixspeed = {"snd_mixspeed", "44100", CVAR_NONE}; #if defined(_WIN32) #define SND_FILTERQUALITY_DEFAULT "5" #else #define SND_FILTERQUALITY_DEFAULT "1" #endif cvar_t snd_filterquality = {"snd_filterquality", SND_FILTERQUALITY_DEFAULT, CVAR_NONE}; static cvar_t nosound = {"nosound", "0", CVAR_NONE}; static cvar_t ambient_level = {"ambient_level", "0.3", CVAR_NONE}; static cvar_t ambient_fade = {"ambient_fade", "100", CVAR_NONE}; static cvar_t snd_noextraupdate = {"snd_noextraupdate", "0", CVAR_NONE}; static cvar_t snd_show = {"snd_show", "0", CVAR_NONE}; static cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", CVAR_ARCHIVE}; static void S_SoundInfo_f (void) { if (!sound_started || !shm) { Con_Printf ("sound system not started\n"); return; } Con_Printf("%d bit, %s, %d Hz\n", shm->samplebits, (shm->channels == 2) ? "stereo" : "mono", shm->speed); Con_Printf("%5d samples\n", shm->samples); Con_Printf("%5d samplepos\n", shm->samplepos); Con_Printf("%5d submission_chunk\n", shm->submission_chunk); Con_Printf("%5d total_channels\n", total_channels); Con_Printf("%p dma buffer\n", shm->buffer); } static void SND_Callback_sfxvolume (cvar_t *var) { SND_InitScaletable (); } static void SND_Callback_snd_filterquality (cvar_t *var) { if (snd_filterquality.value < 1 || snd_filterquality.value > 5) { Con_Printf ("snd_filterquality must be between 1 and 5\n"); Cvar_SetQuick (&snd_filterquality, SND_FILTERQUALITY_DEFAULT); } } /* ================ S_Startup ================ */ void S_Startup (void) { if (!snd_initialized) return; sound_started = SNDDMA_Init(&sn); if (!sound_started) { Con_Printf("Failed initializing sound\n"); } else { Con_Printf("Audio: %d bit, %s, %d Hz\n", shm->samplebits, (shm->channels == 2) ? "stereo" : "mono", shm->speed); } } /* ================ S_Init ================ */ void S_Init (void) { int i; if (snd_initialized) { Con_Printf("Sound is already initialized\n"); return; } Cvar_RegisterVariable(&nosound); Cvar_RegisterVariable(&sfxvolume); Cvar_RegisterVariable(&precache); Cvar_RegisterVariable(&loadas8bit); Cvar_RegisterVariable(&bgmvolume); Cvar_RegisterVariable(&ambient_level); Cvar_RegisterVariable(&ambient_fade); Cvar_RegisterVariable(&snd_noextraupdate); Cvar_RegisterVariable(&snd_show); Cvar_RegisterVariable(&_snd_mixahead); Cvar_RegisterVariable(&sndspeed); Cvar_RegisterVariable(&snd_mixspeed); Cvar_RegisterVariable(&snd_filterquality); if (safemode || COM_CheckParm("-nosound")) return; Con_Printf("\nSound Initialization\n"); Cmd_AddCommand("play", S_Play); Cmd_AddCommand("playvol", S_PlayVol); Cmd_AddCommand("stopsound", S_StopAllSoundsC); Cmd_AddCommand("soundlist", S_SoundList); Cmd_AddCommand("soundinfo", S_SoundInfo_f); i = COM_CheckParm("-sndspeed"); if (i && i < com_argc-1) { Cvar_SetQuick (&sndspeed, com_argv[i+1]); } i = COM_CheckParm("-mixspeed"); if (i && i < com_argc-1) { Cvar_SetQuick (&snd_mixspeed, com_argv[i+1]); } if (host_parms->memsize < 0x800000) { Cvar_SetQuick (&loadas8bit, "1"); Con_Printf ("loading all sounds as 8bit\n"); } Cvar_SetCallback(&sfxvolume, SND_Callback_sfxvolume); Cvar_SetCallback(&snd_filterquality, &SND_Callback_snd_filterquality); SND_InitScaletable (); known_sfx = (sfx_t *) Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t"); num_sfx = 0; snd_initialized = true; S_Startup (); if (sound_started == 0) return; // provides a tick sound until washed clean // if (shm->buffer) // shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav"); ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav"); S_CodecInit (); S_StopAllSounds (true); } // ======================================================================= // Shutdown sound engine // ======================================================================= void S_Shutdown (void) { if (!sound_started) return; sound_started = 0; snd_blocked = 0; S_CodecShutdown(); SNDDMA_Shutdown(); shm = NULL; } // ======================================================================= // Load a sound // ======================================================================= /* ================== S_FindName ================== */ static sfx_t *S_FindName (const char *name) { int i; sfx_t *sfx; if (!name) Sys_Error ("S_FindName: NULL"); if (Q_strlen(name) >= MAX_QPATH) Sys_Error ("Sound name too long: %s", name); // see if already loaded for (i = 0; i < num_sfx; i++) { if (!Q_strcmp(known_sfx[i].name, name)) { return &known_sfx[i]; } } if (num_sfx == MAX_SFX) Sys_Error ("S_FindName: out of sfx_t"); sfx = &known_sfx[i]; q_strlcpy (sfx->name, name, sizeof(sfx->name)); num_sfx++; return sfx; } /* ================== S_TouchSound ================== */ void S_TouchSound (const char *name) { sfx_t *sfx; if (!sound_started) return; sfx = S_FindName (name); Cache_Check (&sfx->cache); } /* ================== S_PrecacheSound ================== */ sfx_t *S_PrecacheSound (const char *name) { sfx_t *sfx; if (!sound_started || nosound.value) return NULL; sfx = S_FindName (name); // cache it in if (precache.value) S_LoadSound (sfx); return sfx; } //============================================================================= /* ================= SND_PickChannel picks a channel based on priorities, empty slots, number of channels ================= */ channel_t *SND_PickChannel (int entnum, int entchannel) { int ch_idx; int first_to_die; int life_left; // Check for replacement sound, or find the best one to replace first_to_die = -1; life_left = 0x7fffffff; for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS; ch_idx++) { if (entchannel != 0 // channel 0 never overrides && snd_channels[ch_idx].entnum == entnum && (snd_channels[ch_idx].entchannel == entchannel || entchannel == -1) ) { // always override sound from same entity first_to_die = ch_idx; break; } // don't let monster sounds override player sounds if (snd_channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && snd_channels[ch_idx].sfx) continue; if (snd_channels[ch_idx].end - paintedtime < life_left) { life_left = snd_channels[ch_idx].end - paintedtime; first_to_die = ch_idx; } } if (first_to_die == -1) return NULL; if (snd_channels[first_to_die].sfx) snd_channels[first_to_die].sfx = NULL; return &snd_channels[first_to_die]; } /* ================= SND_Spatialize spatializes a channel ================= */ void SND_Spatialize (channel_t *ch) { vec_t dot; vec_t dist; vec_t lscale, rscale, scale; vec3_t source_vec; // anything coming from the view entity will always be full volume if (ch->entnum == cl.viewentity) { ch->leftvol = ch->master_vol; ch->rightvol = ch->master_vol; return; } // calculate stereo seperation and distance attenuation VectorSubtract(ch->origin, listener_origin, source_vec); dist = VectorNormalize(source_vec) * ch->dist_mult; dot = DotProduct(listener_right, source_vec); if (shm->channels == 1) { rscale = 1.0; lscale = 1.0; } else { rscale = 1.0 + dot; lscale = 1.0 - dot; } // add in distance effect scale = (1.0 - dist) * rscale; ch->rightvol = (int) (ch->master_vol * scale); if (ch->rightvol < 0) ch->rightvol = 0; scale = (1.0 - dist) * lscale; ch->leftvol = (int) (ch->master_vol * scale); if (ch->leftvol < 0) ch->leftvol = 0; } // ======================================================================= // Start a sound effect // ======================================================================= void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) { channel_t *target_chan, *check; sfxcache_t *sc; int ch_idx; int skip; if (!sound_started) return; if (!sfx) return; if (nosound.value) return; // pick a channel to play on target_chan = SND_PickChannel(entnum, entchannel); if (!target_chan) return; // spatialize memset (target_chan, 0, sizeof(*target_chan)); VectorCopy(origin, target_chan->origin); target_chan->dist_mult = attenuation / sound_nominal_clip_dist; target_chan->master_vol = (int) (fvol * 255); target_chan->entnum = entnum; target_chan->entchannel = entchannel; SND_Spatialize(target_chan); if (!target_chan->leftvol && !target_chan->rightvol) return; // not audible at all // new channel sc = S_LoadSound (sfx); if (!sc) { target_chan->sfx = NULL; return; // couldn't load the sound's data } target_chan->sfx = sfx; target_chan->pos = 0.0; target_chan->end = paintedtime + sc->length; // if an identical sound has also been started this frame, offset the pos // a bit to keep it from just making the first one louder check = &snd_channels[NUM_AMBIENTS]; for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS; ch_idx++, check++) { if (check == target_chan) continue; if (check->sfx == sfx && !check->pos) { /* skip = rand () % (int)(0.1 * shm->speed); if (skip >= target_chan->end) skip = target_chan->end - 1; */ /* LordHavoc: fixed skip calculations */ skip = 0.1 * shm->speed; /* 0.1 * sc->speed */ if (skip > sc->length) skip = sc->length; if (skip > 0) skip = rand() % skip; target_chan->pos += skip; target_chan->end -= skip; break; } } } void S_StopSound (int entnum, int entchannel) { int i; for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++) { if (snd_channels[i].entnum == entnum && snd_channels[i].entchannel == entchannel) { snd_channels[i].end = 0; snd_channels[i].sfx = NULL; return; } } } void S_StopAllSounds (qboolean clear) { int i; if (!sound_started) return; total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics for (i = 0; i < MAX_CHANNELS; i++) { if (snd_channels[i].sfx) snd_channels[i].sfx = NULL; } memset(snd_channels, 0, MAX_CHANNELS * sizeof(channel_t)); if (clear) S_ClearBuffer (); } static void S_StopAllSoundsC (void) { S_StopAllSounds (true); } void S_ClearBuffer (void) { int clear; if (!sound_started || !shm) return; SNDDMA_LockBuffer (); if (! shm->buffer) return; s_rawend = 0; if (shm->samplebits == 8 && !shm->signed8) clear = 0x80; else clear = 0; memset(shm->buffer, clear, shm->samples * shm->samplebits / 8); SNDDMA_Submit (); } /* ================= S_StaticSound ================= */ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) { channel_t *ss; sfxcache_t *sc; if (!sfx) return; if (total_channels == MAX_CHANNELS) { Con_Printf ("total_channels == MAX_CHANNELS\n"); return; } ss = &snd_channels[total_channels]; total_channels++; sc = S_LoadSound (sfx); if (!sc) return; if (sc->loopstart == -1) { Con_Printf ("Sound %s not looped\n", sfx->name); return; } ss->sfx = sfx; VectorCopy (origin, ss->origin); ss->master_vol = (int)vol; ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist; ss->end = paintedtime + sc->length; SND_Spatialize (ss); } //============================================================================= /* =================== S_UpdateAmbientSounds =================== */ static void S_UpdateAmbientSounds (void) { mleaf_t *l; int vol, ambient_channel; channel_t *chan; // no ambients when disconnected if (cls.state != ca_connected) return; // calc ambient sound levels if (!cl.worldmodel) return; l = Mod_PointInLeaf (listener_origin, cl.worldmodel); if (!l || !ambient_level.value) { for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++) snd_channels[ambient_channel].sfx = NULL; return; } for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++) { chan = &snd_channels[ambient_channel]; chan->sfx = ambient_sfx[ambient_channel]; vol = (int) (ambient_level.value * l->ambient_sound_level[ambient_channel]); if (vol < 8) vol = 0; // don't adjust volume too fast if (chan->master_vol < vol) { chan->master_vol += (int) (host_frametime * ambient_fade.value); if (chan->master_vol > vol) chan->master_vol = vol; } else if (chan->master_vol > vol) { chan->master_vol -= (int) (host_frametime * ambient_fade.value); if (chan->master_vol < vol) chan->master_vol = vol; } chan->leftvol = chan->rightvol = chan->master_vol; } } /* =================== S_RawSamples (from QuakeII) Streaming music support. Byte swapping of data must be handled by the codec. Expects data in signed 16 bit, or unsigned 8 bit format. =================== */ void S_RawSamples (int samples, int rate, int width, int channels, byte *data, float volume) { int i; int src, dst; float scale; int intVolume; if (s_rawend < paintedtime) s_rawend = paintedtime; scale = (float) rate / shm->speed; intVolume = (int) (256 * volume); if (channels == 2 && width == 2) { for (i = 0; ; i++) { src = i * scale; if (src >= samples) break; dst = s_rawend & (MAX_RAW_SAMPLES - 1); s_rawend++; s_rawsamples [dst].left = ((short *) data)[src * 2] * intVolume; s_rawsamples [dst].right = ((short *) data)[src * 2 + 1] * intVolume; } } else if (channels == 1 && width == 2) { for (i = 0; ; i++) { src = i * scale; if (src >= samples) break; dst = s_rawend & (MAX_RAW_SAMPLES - 1); s_rawend++; s_rawsamples [dst].left = ((short *) data)[src] * intVolume; s_rawsamples [dst].right = ((short *) data)[src] * intVolume; } } else if (channels == 2 && width == 1) { intVolume *= 256; for (i = 0; ; i++) { src = i * scale; if (src >= samples) break; dst = s_rawend & (MAX_RAW_SAMPLES - 1); s_rawend++; // s_rawsamples [dst].left = ((signed char *) data)[src * 2] * intVolume; // s_rawsamples [dst].right = ((signed char *) data)[src * 2 + 1] * intVolume; s_rawsamples [dst].left = (((byte *) data)[src * 2] - 128) * intVolume; s_rawsamples [dst].right = (((byte *) data)[src * 2 + 1] - 128) * intVolume; } } else if (channels == 1 && width == 1) { intVolume *= 256; for (i = 0; ; i++) { src = i * scale; if (src >= samples) break; dst = s_rawend & (MAX_RAW_SAMPLES - 1); s_rawend++; // s_rawsamples [dst].left = ((signed char *) data)[src] * intVolume; // s_rawsamples [dst].right = ((signed char *) data)[src] * intVolume; s_rawsamples [dst].left = (((byte *) data)[src] - 128) * intVolume; s_rawsamples [dst].right = (((byte *) data)[src] - 128) * intVolume; } } } /* ============ S_Update Called once each time through the main loop ============ */ void S_Update (vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) { int i, j; int total; channel_t *ch; channel_t *combine; if (!sound_started || (snd_blocked > 0)) return; VectorCopy(origin, listener_origin); VectorCopy(forward, listener_forward); VectorCopy(right, listener_right); VectorCopy(up, listener_up); // update general area ambient sound sources S_UpdateAmbientSounds (); combine = NULL; // update spatialization for static and dynamic sounds ch = snd_channels + NUM_AMBIENTS; for (i = NUM_AMBIENTS; i < total_channels; i++, ch++) { if (!ch->sfx) continue; SND_Spatialize(ch); // respatialize channel if (!ch->leftvol && !ch->rightvol) continue; // try to combine static sounds with a previous channel of the same // sound effect so we don't mix five torches every frame if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) { // see if it can just use the last one if (combine && combine->sfx == ch->sfx) { combine->leftvol += ch->leftvol; combine->rightvol += ch->rightvol; ch->leftvol = ch->rightvol = 0; continue; } // search for one combine = snd_channels + MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; j < i; j++, combine++) { if (combine->sfx == ch->sfx) break; } if (j == total_channels) { combine = NULL; } else { if (combine != ch) { combine->leftvol += ch->leftvol; combine->rightvol += ch->rightvol; ch->leftvol = ch->rightvol = 0; } continue; } } } // // debugging output // if (snd_show.value) { total = 0; ch = snd_channels; for (i = 0; i < total_channels; i++, ch++) { if (ch->sfx && (ch->leftvol || ch->rightvol) ) { // Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name); total++; } } Con_Printf ("----(%i)----\n", total); } // add raw data from streamed samples // BGM_Update(); // moved to the main loop just before S_Update () // mix some sound S_Update_(); } static void GetSoundtime (void) { int samplepos; static int buffers; static int oldsamplepos; int fullsamples; fullsamples = shm->samples / shm->channels; // it is possible to miscount buffers if it has wrapped twice between // calls to S_Update. Oh well. samplepos = SNDDMA_GetDMAPos(); if (samplepos < oldsamplepos) { buffers++; // buffer wrapped if (paintedtime > 0x40000000) { // time to chop things off to avoid 32 bit limits buffers = 0; paintedtime = fullsamples; S_StopAllSounds (true); } } oldsamplepos = samplepos; soundtime = buffers*fullsamples + samplepos/shm->channels; } void S_ExtraUpdate (void) { if (snd_noextraupdate.value) return; // don't pollute timings S_Update_(); } static void S_Update_ (void) { unsigned int endtime; int samps; if (!sound_started || (snd_blocked > 0)) return; SNDDMA_LockBuffer (); if (! shm->buffer) return; // Updates DMA time GetSoundtime(); // check to make sure that we haven't overshot if (paintedtime < soundtime) { // Con_Printf ("S_Update_ : overflow\n"); paintedtime = soundtime; } // mix ahead of current position endtime = soundtime + (unsigned int)(_snd_mixahead.value * shm->speed); samps = shm->samples >> (shm->channels - 1); endtime = q_min(endtime, (unsigned int)(soundtime + samps)); S_PaintChannels (endtime); SNDDMA_Submit (); } void S_BlockSound (void) { /* FIXME: do we really need the blocking at the * driver level? */ if (sound_started && snd_blocked == 0) /* ++snd_blocked == 1 */ { snd_blocked = 1; S_ClearBuffer (); if (shm) SNDDMA_BlockSound(); } } void S_UnblockSound (void) { if (!sound_started || !snd_blocked) return; if (snd_blocked == 1) /* --snd_blocked == 0 */ { snd_blocked = 0; SNDDMA_UnblockSound(); S_ClearBuffer (); } } /* =============================================================================== console functions =============================================================================== */ static void S_Play (void) { static int hash = 345; int i; char name[256]; sfx_t *sfx; i = 1; while (i < Cmd_Argc()) { q_strlcpy(name, Cmd_Argv(i), sizeof(name)); if (!Q_strrchr(Cmd_Argv(i), '.')) { q_strlcat(name, ".wav", sizeof(name)); } sfx = S_PrecacheSound(name); S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0); i++; } } static void S_PlayVol (void) { static int hash = 543; int i; float vol; char name[256]; sfx_t *sfx; i = 1; while (i < Cmd_Argc()) { q_strlcpy(name, Cmd_Argv(i), sizeof(name)); if (!Q_strrchr(Cmd_Argv(i), '.')) { q_strlcat(name, ".wav", sizeof(name)); } sfx = S_PrecacheSound(name); vol = Q_atof(Cmd_Argv(i + 1)); S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0); i += 2; } } static void S_SoundList (void) { int i; sfx_t *sfx; sfxcache_t *sc; int size, total; total = 0; for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++) { sc = (sfxcache_t *) Cache_Check (&sfx->cache); if (!sc) continue; size = sc->length*sc->width*(sc->stereo + 1); total += size; if (sc->loopstart >= 0) Con_SafePrintf ("L"); //johnfitz -- was Con_Printf else Con_SafePrintf (" "); //johnfitz -- was Con_Printf Con_SafePrintf("(%2db) %6i : %s\n", sc->width*8, size, sfx->name); //johnfitz -- was Con_Printf } Con_Printf ("%i sounds, %i bytes\n", num_sfx, total); //johnfitz -- added count } void S_LocalSound (const char *name) { sfx_t *sfx; if (nosound.value) return; if (!sound_started) return; sfx = S_PrecacheSound (name); if (!sfx) { Con_Printf ("S_LocalSound: can't cache %s\n", name); return; } S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1); } void S_ClearPrecache (void) { } void S_BeginPrecaching (void) { } void S_EndPrecaching (void) { } �������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/quakespasm.pak��������������������������������������������������������������0000644�0000000�0000000�00002102370�12425635520�016377� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PACKø‚����€�����®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬¬­¬¬¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬­¬­¬¬¬¬¬¬«««¬«¬¬¬­¬¬¬¬¬­¬­¬¬­­¬¬­¬¬¬¬¬­¬¬­¬­¬­®®®®®®®®®¿111¿11¿¿1¿¿1¿¿¿1¿¿¿®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬­¬¬­¬¬­­­­¬¬­­¬¬¬¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬«­«««««¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬®®®®®®®®®®¿11¿1111111111¿¿¿1®®®®®®®®®­¬­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬¬¬­¬«¬««««¬¬¬¬¬¬­­¬¬¬¬­­¬¬¬¬¬¬­¬¬¬¬­­®®®®®®®®®¿¿¿¿¿¿1¿1111¿¿¿¿1¿¿¿¿®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬¬¬­­­¬­­¬¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬­­¬¬­­­¬¬¬¬¬¬­®®®®®®®®¿¿¿¿¿¿¿11111¿¿1¿1¿1®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬­¬¬­¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬«¬¬¬¬««­­¬­­­¬¬­­­¬¬¬­¬¬­¬­®®®®®¿¿¿11¿¿11111111¿1111111111®®®®®®®®®®®¬­®¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬­­­¬­¬¬¬­­­¬¬­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««¬¬¬¬­«¬¬¬¬¬¬­¬­¬­­¬¬¬­­¬¬¬¬¬­®®®®®®®®¿1111¿¿¿111111¿11111111¿®®®®®®®®®®®®®¬­­®­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬­¬¬­­¬¬¬¬­¬­¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬«­««¬¬¬«¬¬¬¬¬¬­¬­­¬­­¬¬­¬¬¬¬¬¬¬®®®®®¿1111¿¿¿¿1¿1111¿1¿1¿1¿¿¿¿®®®®®®®®®®¬¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬­¬­¬­¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬«¬¬¬¬¬««««¬¬¬¬¬¬¬¬¬¬­¬¬¬­­­¬¬¬¬¬®®®®®¿11¿1¿¿¿1¿¿11¿1¿¿¿¿®®®®®®®®®®¬¬®®¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬¬­­¬¬¬¬¬¬­­¬­­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬«««¬¬¬««««««¬«¬¬¬¬¬­¬¬¬¬¬¬­­­¬¬¬­¬¬¬­®®®®®¿¿111¿¿¿1¿¿¿11¿¿¿¿®®®®®®®­®®®®¬¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««¬­¬¬««««¬¬¬¬¬¬­­¬­¬¬¬­¬¬¬¬¬¬¬­¬­¬®®¿11¿¿¿1¿¿1¿¿¿1®®®®®­­¬­¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬¬­¬­¬­¬­¬¬­­¬­­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««¬¬¬«¬­¬­¬¬­¬­¬¬­¬­¬­¬­¬¬¬­­­­®®®®®1¿¿¿¿¿11¿¿¿¿¿¿¿1®®®®®®®®®­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬­¬¬¬¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬­­¬¬¬¬¬«¬¬¬¬¬¬­¬­¬­¬¬¬­­­­­¬¬¬¬¬­¬¬­¬­®­®®®¿¿¿¿1111111¿®®®®®®®®®®®®­­®­­­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬­¬¬¬­­¬­­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬­¬­­¬¬¬­¬¬¬¬¬¬¬¬­­¬­­®®¿¿111111¿¿¿¿¿®®®®®®®®®®®¬­¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬¬¬«¬¬«¬«««¬¬¬¬¬­­¬­¬¬¬¬¬¬­¬¬¬¬­¬¬¬®®®®®¿1¿1¿¿¿¿¿®®®®®®®®®®®®®­®­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­¬¬­¬¬­­¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬­¬¬«¬¬¬«««««¬¬¬­¬¬­¬¬¬¬¬¬¬¬­­­­­­¬¬­®®®®®11¿¿¿1¿®®®®®®®®®®®®®­®­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬¬¬­¬­¬¬­­­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«««¬««««¬¬­­¬¬¬­­¬¬­¬¬¬¬¬­¬­­¬¬®®®®®®®1¿®¿¿¿¿®®®®®®®®®®®®®®®®®®­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­¬­¬­¬¬¬­¬¬­¬¬­¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬­«««««¬««««««««««««««««­¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬­­¬¬¬¬¬­®®®®¿1¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬­¬¬¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­®­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬­¬¬¬¬¬¬¬¬«««««««««««««««««««««««¬«««««¬¬­¬¬¬­­¬¬­¬¬¬­¬¬¬¬¬¬­­­¬­¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬­¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««­¬­¬­­¬¬­¬¬­¬¬­­¬­­¬¬­¬­¬­¬®®¿®¿¿¿®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬­­¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­¬¬¬¬­¬¬¬­¬¬¬¬¬««¬¬¬¬¬¬¬¬¬¬¬«««¬«««««««««««««««««««¬«­¬­¬¬­¬¬­¬¬¬¬­¬­¬¬­¬¬¬¬¬¬­¬¬­¬¬®®®1¿®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬¬¬­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®¬­­­¬¬¬­¬­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬­«¬¬«««««««««¬««««««¬«¬¬­¬¬­­®¬­­¬¬¬­¬¬­­¬¬¬¬­¬¬­¬¬¬­¬­­­­®®¿¿¿®®®®®®®®®®®®®®®®®®­¬¬¬­¬¬¬¬¬­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬¬«««««««««««¬«««««««««««««­¬­¬¬¬¬¬­¬¬­­­¬¬­­¬­¬¬¬¬¬­¬­­¬¬¬­­®®®¿®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®¬­­­­­­­¬¬¬¬¬¬¬­¬¬¬­¬¬«««¬¬¬¬¬¬¬¬««««««««««««««««««««««««¬¬¬­¬­­¬­¬¬­¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬­­­®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬­­¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­­­¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬«««««««««««««««««««««¬¬¬¬¬¬­¬­¬­­¬­¬¬­¬­­¬¬¬¬¬­¬¬­¬­¬­®®¿1¿1¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬­­­¬¬¬¬­¬¬¬¬­¬¬«¬¬­¬¬¬­¬­¬¬¬¬¬¬¬«««««««««««««««««««¬¬¬­¬­­¬¬¬¬¬­­¬¬¬¬¬¬­­¬¬¬¬¬­­¬¬­­®®®®®¿¿1¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­­­­¬¬¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬«¬¬¬¬­¬¬¬¬¬¬««««««««««««««««««««««««¬¬¬¬­­­¬­¬­¬¬­¬­¬­¬¬­­­¬¬¬¬¬­¬¬¬­®®®®¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®­­­¬¬­¬¬­¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««­««««««««««««««««¬«««««««¬¬­¬¬­¬­¬¬®¬¬­¬¬¬¬¬­¬¬¬¬­¬­¬¬¬¬¬¬®®®¿¿¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬¬¬¬¬¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­­­­¬­¬¬¬¬¬­¬¬¬¬­­¬¬¬¬¬¬««¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««¬¬¬­¬¬¬¬­¬­­¬¬¬¬­¬­¬¬¬­­¬¬¬¬¬­¬­¬¬­¬­®®¿11®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬¬¬¬­¬¬¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­¬¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬¬¬««««¬¬¬¬¬¬¬¬¬¬««««««««««««««««¬­¬¬¬­¬¬¬­¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬­®¿®¿¿®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬­¬¬­¬¬¬¬­¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««¬¬¬¬¬¬¬«««««««««««««««««««««««¬¬¬«¬¬¬­¬­­­­¬¬¬­¬¬¬¬¬­¬¬¬¬­­®¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬¬¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­­¬¬¬­­­¬¬­¬¬­¬¬­¬¬¬­¬­¬¬¬¬­««¬¬¬¬«¬«««««««««««««««««««««««¬¬­­¬­®¬¬¬¬­­¬¬¬¬¬­­¬¬­­¬¬®®®¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­¬¬¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­¬¬­¬¬­­­¬¬¬­­¬¬¬¬­¬­¬¬««¬¬¬¬¬««¬«««««««««««««««¬««««¬¬¬­­¬®®®¬¬¬¬¬¬¬¬¬¬­­­¬¬­¬­¬¬¬¬¬¬­®®®¿¿¿1¿®1®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬­¬¬­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬¬¬¬­¬­­¬¬­­­¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬«¬¬«¬¬¬¬«««¬¬«¬«¬¬¬¬­¬¬­­®®®­­¬­¬¬­¬­­¬­¬¬¬­­­¬­­­¬­­®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­¬­¬¬­¬¬¬¬­¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­¬¬¬­¬¬¬­¬¬¬¬¬­­¬­¬¬¬¬¬««««¬«¬«¬¬¬¬«¬¬¬¬¬¬¬¬¬¬­®­¬­¬¬¬¬¬¬­¬¬­¬¬¬¬­¬­­­¬­®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬­­¬­¬¬­¬¬­¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­¬­­¬­­­­¬­­¬¬¬¬­¬¬­¬¬¬­¬¬«¬«¬«¬¬«¬«¬¬¬¬¬¬«¬«¬¬¬¬¬¬­¬¬­­­­¬­¬¬¬¬­¬¬¬¬¬­¬¬­­­­®®®®®®®¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬­¬¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­­¬¬­¬­­­­­­¬­¬¬¬¬­¬¬­¬¬¬¬¬¬««¬¬¬¬«««¬««««¬«¬¬¬¬¬¬­­¬­¬¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬­¬¬­¬­­®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬­¬¬¬­¬­­¬¬¬¬¬­¬¬­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­­¬­­¬­­­¬¬­¬¬­¬¬¬­­¬­¬¬«««««««««««««¬¬¬¬«¬¬¬¬¬¬¬¬¬¬­­¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬­¬¬¬®®®®®®®®®®®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬­­¬­­¬¬¬¬¬¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬¬¬­®¬¬¬­­¬¬­¬¬¬¬­¬¬¬««««««««««¬¬¬¬¬¬¬¬­¬¬««­¬¬­¬­­¬¬­¬¬­­­¬¬¬­­¬¬­¬¬­­¬¬­¬¬®®®®®®®®®®®®¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬­¬­¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬­­­­­­­­¬­¬¬¬¬¬¬­¬¬­¬¬¬¬«¬«««««¬¬¬¬««¬«¬¬­­¬¬¬«¬­¬­¬¬¬¬­­¬¬¬¬­­¬¬¬¬­¬¬­¬¬­¬¬­®­®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬¬­¬¬­¬­­­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬­­­¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬¬¬«««¬¬¬¬««¬¬¬«¬¬¬¬­¬­¬­­­­¬¬¬¬¬¬­­¬­¬­¬­¬¬­®¬­¬®®®®®®®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬­¬­¬¬¬¬­­­¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­­®­­¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬««««««¬¬¬¬¬¬¬­­¬¬­¬¬¬¬¬¬­¬¬¬¬­­¬¬­­¬¬¬¬¬­­­®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬¬­­¬­¬­­¬¬¬¬­¬­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬¬¬¬­­®­­¬¬¬­¬¬¬¬¬­¬¬¬¬­¬«««¬­¬¬¬«¬¬«¬¬¬¬«¬¬¬«¬¬¬¬­¬­­¬¬¬¬¬­­¬­¬­¬¬®­­¬¬­®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­¬­¬¬­¬¬¬­­¬¬¬­­­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬®®¬­­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬«««¬¬¬¬¬¬««¬«¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬­¬¬¬¬¬­­¬¬­¬­¬­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬­¬¬¬¬¬­¬­¬¬¬­¬­¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­®­¬¬¬¬¬¬­­¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬«¬­¬¬­¬¬­¬¬¬¬­­¬¬¬¬¬¬¬¬­¬­¬¬¬¬­¬­­­­­¬­®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬­­¬¬¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬­­­¬­¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬«¬««¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­­¬­¬¬¬¬­¬¬¬¬­¬­¬¬­¬¬­­¬¬¬¬­¬®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­­­­¬¬¬¬­¬¬­¬¬¬¬­¬¬­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬­­­­­­­­­­¬¬¬¬­¬¬­­¬­¬¬­¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬«¬¬¬­­¬¬­­¬­¬¬­¬­­¬­­¬­¬¬¬¬¬¬¬¬­®­®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬­¬­­­¬¬¬­¬­¬­­¬¬¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬­­­­¬­­­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬««««¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬¬­­¬¬¬¬¬¬¬­¬¬¬­¬­¬¬­­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬­¬­¬¬­¬¬­¬¬¬¬¬­­­­­®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­­­­­­­­­­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬«¬««¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬­¬­­­­¬¬­¬¬¬¬­¬­¬¬­®¬¬­­­­®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬¬¬¬­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬­¬­¬®®­®­¬­¬¬­­­¬¬­­¬­¬­­¬­¬­­­¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬­­­¬¬¬¬¬­¬¬­­­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­­­­­­¬¬¬­¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬««¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬­­­¬¬­¬­¬¬¬¬¬¬¬­­¬­¬­­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­¬¬­¬­¬¬¬­¬¬¬­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­­­­¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬«¬«««¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬«¬¬¬¬¬¬¬­¬®­­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­­¬¬®­¬­­®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­­¬¬¬¬­¬¬¬­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­­¬­¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬«¬¬¬¬«¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬®®¬¬­¬¬®­¬¬­¬¬¬¬¬¬¬¬­¬­­­¬®®®®®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬­­®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­­¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬­¬®­­­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­­¬¬®­­®®®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®¬¬¬¬­¬¬­¬­¬­¬­­­¬¬­¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬««¬¬­¬¬­¬¬¬¬¬­­¬¬¬¬¬¬­¬¬­¬¬­®­­®­¬®­­¬¬­¬¬¬¬­­¬­¬­®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®¬¬¬­¬¬­­¬¬¬¬¬¬¬­¬¬­­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬««¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­­®®®­¬¬¬­¬¬¬¬­­¬¬­®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬­¬­¬­¬¬­­¬¬¬¬­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­­­¬¬­­­­­­­­­¬¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬­­­¬­®¬¬­¬¬¬­¬¬­­­­­­¬¬®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬­­¬­¬¬­¬­¬¬­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­®¬¬­¬¬¬¬¬¬¬­¬¬¬¬­¬­­­­®­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­¬¬¬¬¬¬­¬¬¬­¬­¬­¬¬­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­­­­¬­¬­­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬««¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬­­¬«­¬¬¬¬­­­¬­­¬­­¬¬¬­­­¬­¬¬­¬®®­¬¬¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­¬¬­­¬­¬­¬­­­­¬¬­¬­®®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬¬­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬«¬«¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬«¬¬¬¬¬¬­¬¬¬¬¬­¬­¬¬¬­­­­¬¬­¬¬®­¬¬¬¬­­¬®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬­¬­¬¬­¬­­­¬¬­­¬®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬«¬«¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­­­¬¬¬¬¬¬¬­­¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­­¬¬¬­­¬­­¬­­¬¬¬®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­®­­­®¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬«¬«¬¬¬¬¬¬­­¬¬¬¬¬¬¬­¬­¬¬¬­¬­­­­­­¬­¬­¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬­¬¬¬­­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­®¬¬­­­­­¬¬¬­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬®­¬¬­¬­¬¬¬¬¬­¬­­­¬¬­­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬¬­¬¬¬­­¬¬¬­¬­­¬­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬¬­­­¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­­­­­¬­­¬­­¬¬­¬­¬¬¬¬­­­¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­­­­¬­­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬«««««¬¬¬¬«¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬­­¬¬¬¬­¬¬¬­­¬¬¬¬¬®­­¬­¬­¬­¬­¬¬­¬­®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬­¬¬¬¬¬¬­­¬¬­­¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬­¬¬¬­¬¬­¬¬­¬¬­­¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬¬­­¬¬­­¬­®®®®®®­­®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬­¬¬¬­¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­¬­¬­¬¬¬¬¬¬­¬¬­¬­¬­¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬­­¬¬¬¬¬¬¬¬­¬¬®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­¬­­¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬¬®­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬­¬­¬­¬¬­¬¬­­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬­¬¬¬¬­­­¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬¬¬­­­­¬¬­¬®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬¬­¬­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®¬­¬­¬­¬¬­¬­­¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­­®¬­­­­­­®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬¬¬¬­¬­¬­¬¬­¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬­­¬­¬¬­­­­¬¬­­¬¬¬¬­¬¬­¬¬¬­¬­¬¬¬¬¬­¬­¬¬¬¬¬¬­¬­¬­¬¬¬¬¬¬¬­¬¬¬­¬­¬­¬¬¬¬¬¬¬¬¬­¬¬­­­­­¬¬­¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­­¬¬­¬­­¬¬­­­¬¬­¬­¬¬¬¬¬­­­¬¬¬¬­¬­­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬¬¬¬¬¬­­¬­¬¬¬¬¬¬­®®­®®®­®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®¬­­¬¬­¬­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­­­¬¬­¬¬¬¬¬¬¬­¬¬­­­­­¬­­­¬¬¬­¬­¬¬¬¬¬­¬¬¬¬­¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­­­¬­¬®®¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬®­®®®¬­¬­¬­¬¬­¬¬­¬¬¬­¬¬­¬¬¬¬­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®­¬­¬¬­¬¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬­¬­­¬¬¬¬­­¬¬­¬¬­¬¬¬¬¬¬­­¬¬¬¬­¬¬¬¬­¬¬­¬­¬¬­¬¬¬­­¬¬­¬¬­­¬¬¬¬¬­­¬¬­¬­¬®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬®®®®®®®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬¬¬­¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬­¬¬­­¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬­¬¬¬¬¬­¬¬¬­­¬­¬¬¬¬¬­­­­®®®®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬­¬¬­­¬­¬¬¬¬¬­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬­­­¬¬­¬­¬¬¬¬¬¬¬¬¬­­¬­¬­¬¬­¬­­­­¬¬¬¬­¬­¬®­­­­®®­®®®¬­®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬¬¬¬¬­¬¬¬¬­­¬¬¬¬­¬­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­­¬¬¬­­¬¬­¬¬¬­¬¬¬­­¬¬­¬­¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬­®­­­­®®®®¬®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬­®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­¬¬­¬¬­¬¬­¬­¬­¬­¬¬¬¬¬­¬¬¬­¬¬¬¬­¬¬¬¬­¬­¬¬­¬­¬¬­¬­­¬¬¬¬­¬­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬®­­­®®®®®®®®®®®®®®®®®®®11¿®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬¬¬­¬¬¬­¬­¬¬­¬­­¬®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬­­¬­­­­¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬­¬­­¬¬¬­¬¬­¬¬¬¬¬¬­¬¬­¬­¬­­¬¬¬­­¬¬¬¬¬¬­¬¬­¬¬­¬¬­­¬­­¬­­­­­¬¬¬®®®®®®®®®®®®®®®®®®®¿¿1®®®®®®®®®®®®®®®®®®­¬­­­¬¬¬¬¬¬¬­¬­¬¬¬¬®¬¬¬¬®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬¬­­¬¬­¬­¬¬­¬¬¬¬­¬¬¬­¬¬¬­­¬¬¬­¬­¬¬¬¬¬¬­¬¬¬¬­¬­¬¬¬­¬¬­­¬¬¬¬¬¬¬­­¬¬­¬¬¬¬­­¬­¬¬¬¬¬¬­¬¬¬¬­¬­¬­¬­­­¬®¬¬­­¬¬­®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬­¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­¬­¬¬¬¬¬¬¬­¬¬­­¬¬¬¬¬¬­¬­¬­­¬¬­¬¬¬¬­¬¬¬¬¬­¬­¬¬¬¬­­¬¬¬¬¬¬¬¬¬­¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬®¬­¬­¬¬¬¬®­®®®®®®®®®®®®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬®¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®¬¬¬¬¬­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬­¬­­¬­¬­¬¬¬¬¬¬­­¬­¬¬¬¬­¬­­¬¬¬¬¬¬¬¬­¬¬®­®®®®®®®®®®®®®®®®®®®¿1®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬­¬¬­¬¬¬­¬¬¬­¬­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬­¬¬­¬­¬¬­¬­­¬­¬¬­­¬¬­­¬¬­¬¬¬­¬­¬¬¬­­¬­®­®®®¬®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®¬®­¬¬¬¬¬­­¬¬¬¬¬¬­¬­¬¬­¬¬¬¬¬­¬¬­¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­¬¬¬­¬­­¬­¬¬­¬¬¬¬­¬¬­­¬­¬¬¬­­¬¬­­¬¬¬­­­¬­¬¬¬¬¬¬­¬¬¬¬¬®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­¬¬¬¬­¬¬­¬¬­¬¬­¬­­¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬­¬¬¬­¬¬¬¬­¬¬¬¬­¬­¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬­­­¬­¬¬­¬­­®®­­®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­­¬¬¬­¬¬­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬­¬¬­¬¬¬­­­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬­­¬¬­¬¬­­¬­¬¬¬¬¬¬¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬­¬­­¬­¬¬­­­­®®­­¬¬®®­®®®®®®®®®®®®®®¿¿®®®®®®®®®­¬­¬¬¬­¬¬¬¬¬­¬¬­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­®­­¬­¬¬¬¬­­¬¬­­¬¬¬¬­¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬­¬­¬¬­¬­¬¬¬¬¬¬¬­¬­¬¬­¬­¬¬¬¬¬­­¬¬­­¬­­¬¬¬¬­­¬¬¬¬­¬¬¬¬­¬­¬®®­­®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬¬­¬­®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®¬­¬¬¬¬­­­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬­­¬¬¬­­¬¬­¬¬¬¬¬¬­­¬¬­¬­¬¬¬¬­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬­¬¬¬­­­­¬¬­¬¬¬¬¬­¬¬¬¬¬¬®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬­¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬­¬¬¬¬­¬¬­¬¬­­¬­¬¬¬¬­­¬¬­¬¬¬¬­­¬¬­¬­¬¬­­¬­¬¬¬¬­­­¬¬¬¬¬¬¬¬¬­¬¬­­­­­­¬®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬®¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬­­­­­¬¬¬­­¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬­¬¬¬­­¬­­¬¬­­­­­­®­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬®®­®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®­­¬­¬¬­­­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬­¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬­­­¬¬¬­¬¬­­¬¬­¬¬­¬¬¬¬­­¬­¬­­¬­­¬¬­¬¬¬¬¬¬®­¬®­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬®­®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬®®®¬¬¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬­¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­­¬¬­¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬­¬¬­¬­­¬¬¬¬¬­­¬¬­¬¬¬¬¬­¬­¬¬­¬­­­¬­­­¬®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­¬­¬¬¬­¬¬¬¬­­­¬¬¬¬¬­¬¬¬­¬­¬¬­¬­¬­¬¬¬¬­¬­¬¬¬¬­­¬¬­¬¬­¬¬¬­¬¬¬¬­¬­¬¬­¬­¬¬¬¬¬¬¬¬¬­­¬­¬­¬­¬¬¬­­­¬®­¬­¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬¬¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬­­¬¬¬¬­¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­­¬¬­¬¬¬¬¬¬¬­¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬­¬¬­¬¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­­­­¬­­¬¬­­¬¬­¬­¬¬­­¬¬¬¬­¬­­¬¬­­­®­¬­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬­¬¬­¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­¬¬­­­¬­¬¬¬¬¬­¬¬­¬¬­¬¬¬­¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬¬­¬¬¬¬­­¬¬­­­¬®­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­­¬¬¬¬¬¬­¬­¬­¬­¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬®®®®®®­¬¬¬¬¬¬­¬¬­­¬­¬­¬¬¬¬¬­¬¬¬¬¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬­¬­¬­­¬¬­¬­¬¬­­¬¬¬¬­­¬¬­¬¬¬¬­¬­¬­¬¬­¬­­­­¬®¬­­­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬­¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬­¬­¬¬¬¬¬¬¬¬¬­¬¬­­¬¬¬¬­¬¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬­­¬­¬¬­¬¬­¬­¬¬¬¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬­¬¬¬­¬­­­­­¬­¬­­­¬¬¬®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®­­¬­­¬¬­¬¬¬¬¬¬¬­­¬¬­­¬¬¬¬¬­¬¬­¬¬­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬­­¬¬¬¬¬¬¬¬­¬­¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬®¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬­­­­¬­­¬­¬¬¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬¬­¬­­­­¬¬¬­­¬­­­­­­®®®®®®®®®®®®®®®®¿®®®®®®®®®­­­¬¬­¬¬¬¬¬­¬­¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬­¬¬¬¬¬®®®®®®11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­­­­¬¬­­¬­¬¬­­­¬¬¬¬­­¬¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬­­¬¬¬¬¬­®¬¬®­­­­­¬­­­­­­¬¬­­­­­­®®®®®®®®®1®¿®®®®®®®®®®®®®®®­¬¬­¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬­¬¬­¬¬­­¬¬­¬¬­¬­®®®®®®®®®®1111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬­¬­­­¬­­­­­®­­­­¬¬­¬¬­­¬¬­­¬¬­¬¬¬¬­¬¬¬­¬¬­­­¬¬¬¬­¬­¬­­­­­­­­­¬­­­¬­¬­­­­®®®®®®®®®1®1®®®®®®®®®®®®®®¬¬¬¬­­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬­¬®®®®®®1¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬¬¬­­­­­­­­­­­¬¬¬¬­¬­­­¬­¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬¬­­¬¬¬­­­­¬­­­­¬­­­¬­­­®®®®®®®1¿¿®®®®®®®®®®®®®®®®®®¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬­¬¬¬¬­¬­­®®®®®®®11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­¬¬­¬¬­­­­­­­­­­­¬­¬­­¬­¬­­­¬¬¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬­¬­¬­­¬­¬­®®­­­­­­®­­¬­­­­­¬­¬¬¬¬¬®®®®®®®®¿1¿¿®®®®®®®®®®®®®®®®®¬­­¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬­¬­¬­¬¬­®®®®®1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬¬­­­­­­¬­­­­­­­¬­­­¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬¬­¬¬­­­¬­¬¬¬®­­¬­­®­­¬¬­¬¬­­®®®®®¿®®®®®®®®®®®®®®®®®¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬­­¬¬¬­¬­¬®®®®®®®®11¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­¬­¬¬­­­­¬¬¬¬­­­¬¬¬¬­­¬¬¬¬­¬­¬¬­¬¬¬­¬­¬¬­­­­­­¬®­­¬­­­­¬¬­­­®®®®®¿1¿®®®®®®®®®®®®¬¬¬­¬­¬¬¬¬­¬¬­¬­¬¬¬¬¬¬¬­¬­®®®®1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­­­­­¬­¬¬¬­¬¬¬¬¬­¬¬¬­­¬¬­­¬­¬­¬¬­¬­­­¬¬­¬¬­­®¬¬­­­¬¬¬¬­®®®®®®®®¿¿®®®®®®®®®®®®­¬¬­¬¬¬¬­­­¬­¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬®®®®1¿¿1¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬­­¬¬®­¬­­¬¬­¬­®­¬¬­­¬¬¬¬¬¬­¬¬¬­¬­¬­­­­¬­¬­­­­­­®®®­¬­­¬­­­­®®®®®®®®®®¿®®®®®®®®®®®®®®®®®¬¬­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬®®®®®®111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬­¬¬¬¬­­¬¬­®­¬¬­¬­­¬¬¬¬¬¬­­¬¬¬­¬¬¬¬¬¬­­¬¬­¬¬­®­­­®­¬­¬­­¬­­¬­­­­®­®®®®¿¿1¿®®®®®®®®®®®®®®®®®¬¬¬­¬­¬¬¬­­¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬®®®®®®®®11111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬­­¬­­¬¬¬­®­¬­¬¬¬­¬¬¬­¬¬¬¬¬¬¬­¬­¬¬­­­®¬­­®­­¬¬­¬­­­¬¬¬­­®®®®®1¿¿1¿¿®®®®®®®®®®®®®®¬­­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­®®®®®1111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­¬­®®®¬¬­¬­¬­¬¬¬­­¬¬­¬­¬¬¬­¬¬­¬­­¬¬­­­®­®®®­­®­­­­­¬¬¬¬¬­¬¬¬¬¬­®®®®¿11111®®®®®®®®®®®®®®®­¬­­¬­¬¬¬¬­¬¬¬­­­¬¬¬¬¬¬­­¬¬¬¬¬­¬¬®®®®®®®¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­¬­­¬­¬­¬¬­¬­¬¬­¬¬¬­­¬¬­¬¬¬¬¬­¬¬¬¬­­­­¬­­¬­­­­¬¬¬¬­­­¬¬­­¬¬¬­­¬¬­­®®®®®®®®11¿¿®®®®®®®®®®­¬¬­¬­¬¬¬¬¬­¬®¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬®®®®11¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­­­­­¬­®®®­¬­¬¬­¬¬¬­¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬¬­­­¬­¬¬­®¬­¬­¬¬­­¬¬¬¬¬¬¬­­¬®®®¿1¿¿®®®®®®®®®®®®®­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬®®1111¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­®®­­­­®¬¬®¬¬¬­¬¬­¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬­¬­¬¬­¬¬­­­­®­¬­­­­¬¬­­¬¬¬¬¬­­­­®®®®®®¿¿¿¿®®®®®®®®®®®®¬¬¬­­¬­¬¬¬­¬¬­­¬­¬¬¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬­¬®®®1¿11¿1¿¿1¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­­®­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬­¬­®®­­®®­­¬­¬¬­¬¬¬®¬¬¬¬¬¬®®®®®¿¿11¿¿¿®®®®®®®®®®®®®®­­­¬¬­­­¬¬¬¬¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬®®11111¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬®­­¬­­¬­¬­¬­­­¬­¬¬¬­­¬¬¬¬¬­¬­¬¬­¬¬¬¬­­¬­®®¬­®¬­­­¬¬­¬­¬¬­®¬­¬­­­®®®®®®®®®®¿¿¿¿¿11®®®®®®®®®®®®®®®®®®®­¬¬­¬­¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬­­¬®®111¿1¿¿¿1¿¿¿¿¿¿¿1¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­¬­­­¬­­­¬­­¬¬­­­¬­¬­¬¬­­®®®®®®®®®®®®®®­­¬¬¬¬­­¬­­®®®®®®®®®®®®®®®®¿¿¿11¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­¬¬¬­­¬­¬¬¬¬­¬­¬¬­¬­¬­¬¬­­¬¬¬¬­¬­¬¬®1¿1111¿1¿1111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬®¬­¬­­¬®­¬­­­­­­­­­¬¬­¬­¬¬­¬¬¬­­®­®®®®®®®®®®®®®®®®®®­­­­­¬¬¬­­­¬­­®®®®®®®®®®®®®®®®®®®1¿1¿¿1¿1¿1¿®®®®®®®®®®®®®®®®®­¬¬¬­­¬¬¬¬­¬­¬¬­¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬­­¬¬¬111¿111¿1¿¿¿1¿1111¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­¬¬¬­­­­¬­¬¬¬¬¬¬¬­®®®®®®®®®®®®®®¬­­­­¬¬¬¬­¬­­¬­®®®®®®®®®®®®®®®®®®¿1¿¿¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬­¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬®­11¿1111¿11¿¿1¿¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬­­¬¬­¬­¬­­­¬­®®®®®®®®®®®®®®®®®®¬®­¬¬¬­¬¬¬¬­¬­­­­®®®®®®®®®®®®®®1¿¿¿1¿¿¿11¿11111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬­¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­­¬®111111¿¿111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬¬­¬¬­¬¬­­¬­®®®®®®®®®®®®®®®®®®®®­¬¬­¬­¬­­®­­­­®®®®®®®®®®®®¿¿¿¿111¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­¬¬­¬¬¬¬¬­¬­¬­¬¬­¬¬¬¬­­¬­¬­¬¬­¬­¬­¬¬¬­­­®¿1111¿1¿¿¿¿1¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­¬¬¬¬¬¬¬­­®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­®®®®®®®®®®®®®®¿11111111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬¬­¬¬¬¬¬­­¬­¬­­¬¬­¬¬¬¬­¬¬­­­­¬­®¿111¿¿1¿11¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®¬¬¬­­¬¬­­®®®®®®®®®®®®®®®®®®®®®®®­­­­®®®®®®®®®®®®®111¿111111111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­¬­¬¬­¬­¬¬­¬¬¬¬¬¬­­¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬®¿111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬¬¬­¬­­®­­®®®®®®®®®®®®®®®®®®®®®®®®®­­¬®®­®®®­®®®®®®®®¿1111¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬­®®1¿1¿1¿¿¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬­­¬­¬­¬¬¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®­®®®®®®®11¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬¬­¬¬¬­­¬­­­®®®®®¿¿1¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­¬­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®­®®®®®®®®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬­¬­­¬¬¬­¬¬­¬¬¬¬­¬¬­¬¬­­­¬­­®®®¿1¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®¬­­­­­­¬­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬­®¿1¿¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬¬¬¬­­¬­¬¬¬¬­­¬¬­¬¬­¬¬­¬¬­¬¬­­­®®®1¿¿1¿11¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬­­¬­¬­®®®­¿1¿¿1¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬¬­¬­¬­­¬¬­¬­­­­¬¬®®¿1¿¿1¿¿¿¿11¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬­¬¬­®®®¿¿¿1¿¿1111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬¬­¬­­¬¬¬¬­¬¬¬¬¬­¬¬¬­¬¬®®®¿¿®¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬­­¬¬¬¬¬­¬­¬­¬¬¬­­¬­¿¿¿1¿¿¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­®®­¬¬­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­­¬¬­¬¬¬­¬¬¬¬¬­­¿¿¿¿®¿¿1¿¿11¿¿¿¿¿¿1¿¿¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­­­¬¬¬­­­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬­¬¬¬­¿¿1¿¿®¿1¿¿¿¿¿¿¿¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿1¿11¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬­¬¬¬¬1¿¿¿¿1111¿¿¿¿¿¿¿¿¿¿1¿¿¿¿11111111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿1¿1¿¿1¿11¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®­¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬«¬¬­¬¬¬¬­­¬¬¬­¬¬¬­¬1¿¿¿¿1¿1¿¿111111¿¿1¿11111¿¿¿¿¿¿¿¿¿¿1111111111¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿1¿¿¿¿¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿¿¿¿1¿11¿111®®®®®®®®®®®®­®®®®®®®®®®®®®¬¬®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬­­¬¬¬¬¬­¬¬¬««¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¿¿1¿¿¿¿¿11¿1111111111111111111¿11¿1¿¿1¿¿1¿¿11111111111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿1¿¿1¿¿1¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®¿1¿¿¿¿1¿1¿11®®®®®®®®®­­®®®®®®®®®®®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬¬¬¬¬¬­¬­««««¬¬¬¬¬¬¬¬¬¬¬¬¿¿1¿¿¿¿¿1¿¿11¿¿11111111¿¿¿1111111111¿11¿¿¿¿¿¿11111111111¿¿¿1¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿¿1¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®¿11¿¿¿1®®®®®®®®­­­­­­¬­­®®®®®­®®®­¬¬­®®®®®®®®®®®®®®®®®®­¬¬¬««««¬«««««¬¬¬¬¬­¬­¬¿¿¿¿¿1¿1¿¿11¿¿111¿¿¿11111¿1¿¿¿¿¿111111111111¿¿¿11¿1111111111¿1¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®111¿1¿1®®®®­­¬¬¬­­¬¬­®®®®®®®­®®®®®­®¬®®®®®®®®®®®®®®®®®®®®®®®®®­¬­®®¬¬­¬««««««¬«««««««««««««««««¬¬¬­¬¬¬¬¬¿¿¿1¿¿11¿¿¿111¿¿1¿¿1¿¿¿11¿1¿11¿¿¿¿¿1¿111111¿1¿1¿¿11111111111111¿¿¿¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿111¿®­­­­­­­­¬®®®®­®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬««««««««¬««««««««««««««««««««¬¬¬­¬¬­­¿¿¿¿¿¿¿¿¿111¿¿¿11¿¿¿11¿¿111¿¿¿¿¿¿¿¿¿¿1¿¿1111¿¿111111111111¿¿1¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­­¬¬­¬®®®®­®®®¬®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®­­¬¬­¬««««««««««««««««««««««««««¬¬¬­¬11¿1¿¿1111¿¿¿1¿¿¿11111111111111¿1111111111111¿¿1¿11¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬¬­­­­­¬­­­¬­­­®­­­­¬­®®®®®®®­¬¬­­¬¬¬¬¬««««««««««««««««««««««¬¬¬¬¿111¿111111¿¿¿1¿¿¿1¿1111111111111111111111111¿11¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­­­­­­¬¬¬­¬­­¬¬¬¬­¬¬­¬­­­­­­¬­®­­­­­¬­¬­¬­®­®®®®®®®®®®¬­­¬¬­¬¬­¬¬¬¬«««««««««¬«««««««««««¬««¬¬¬¬11¿¿1¿¿111¿111¿¿¿1¿11111111111111111111111111¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®¿®®®®®®®®®®®®®¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬¬­¬¬­¬¬­¬­­­­­­­­¬¬¬¬¬­¬¬­­¬¬¬¬¬­¬®®®®®®®®®®®®®®®­­¬¬­¬¬­¬¬««««««««««««««««««««««««««««¬¬¬¬¿11111¿¿¿¿111¿1111111111111¿¿¿¿1111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­®®®®®®®®®®®®®®®®®®­®®®®®®®¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­¬¬¬¬­¬¬¬­¬¬¬¬­¬­­¬¬­¬­¬¬­­¬¬¬­¬¬¬¬­¬¬¬¬¬¬®®­®®®®®®®®®®®¬­­­­¬¬¬¬¬««««««««««««««««««««««¬¬¬­¬¬¬111¿¿¿¿¿¿¿¿¿11111111¿¿¿¿¿¿111®®®11¿®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬¬­¬¬­¬¬­­¬¬¬¬¬­­¬¬¬¬¬­¬­­¬­¬¬¬¬¬¬­¬­¬­­®®®®®®®®®®®®®®®¬­­­­¬­¬¬­¬¬««««««««««««««««««««««««¬¬­­¬¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿1®®®®­­®®®®®®®­­®®®®®®®®®­­­­­¬¬¬¬¬¬­­¬¬­­¬­­¬­¬­¬¬­­­¬¬­­¬­­­¬¬¬­­¬­­¬­¬­¬¬­­®®®®®­­®®®®®®®®®®®¬­¬­­­¬¬¬¬­­¬­­¬¬­®®¬¬­¬¬­««¬«««¬««««««««««««¬¬¬­¬¬¬¬­¬­¬­­­­­¬¬¬¬­¬­¬¬¬­¬««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­®®®­®®­­­¬¬­­¬¬­¬¬¬­­­­­­¬­¬¬¬¬¬­¬¬­­¬­­­¬­¬­¬¬­¬¬­­¬­¬¬­­¬­­­­­­®®­®®®®®®®®®®­­­¬­¬­­¬­¬¬­¬­­­­­­­¬­®®®¬¬¬««««««««««««««««««««¬­­¬­­¬­­­®­¬¬­¬¬¬­­¬«««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬­¬¬¬­­­­­­¬­¬¬­¬­¬¬­¬­­¬¬­¬¬¬­­¬­¬¬­­¬¬­­­­®®­®®®®®®®®®­­¬­¬¬­¬¬­¬­­¬­¬¬¬¬­­­­­¬­¬¬­®­­®®®¬­®¬¬¬¬¬«««««««««««««««««««««««««­¬­­­­¬¬¬¬­¬¬¬¬­­­¬­¬¬¬­«¬«««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬­®­­®­­­­¬­¬¬­¬­­­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬­¬­¬¬¬¬­­¬¬¬­­¬­­­­¬¬¬¬¬­­¬­­­­­¬¬®®®®®®®®®®®®®­¬­­­­­¬­¬¬­¬­­¬­¬­­¬¬­­­­­­­¬¬­¬¬­¬«««««««««««««««««««««««¬­¬¬¬¬­­¬­¬¬¬­®­­¬­¬­­¬««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®­­¬¬­¬¬­­¬¬¬¬­­¬¬¬­¬­¬¬¬¬¬­­¬¬¬¬¬¬­­¬­¬­­¬¬­¬¬¬­­­­¬¬¬®®®®®®®®®®®®®®®­­­­­­­¬¬­¬¬­¬­¬¬­¬¬­­¬¬­­¬¬¬­­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««¬­¬¬¬­¬¬­¬­­¬®­¬­¬¬­­««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­­­®¬­¬­¬¬­¬¬­¬¬¬­­­¬¬­¬¬¬¬¬¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬­¬­­¬¬¬­¬¬¬¬­¬­­¬¬¬­®®­®®®®®­¬­­­­­­¬¬­¬¬­­­¬­¬­¬­­­­¬¬­¬­¬¬¬¬­¬¬¬««««««««««««««««««««««¬¬¬¬¬­­¬­¬­¬­­¬¬®¬­­¬«««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­­­®­­­­­­­­­­­­­­­®­¬¬¬¬­­­­¬¬­¬¬­¬¬­¬­­¬¬­­¬¬­¬­¬¬¬­¬¬­¬¬¬­­­­­­¬­¬¬­¬¬¬¬­¬¬­­¬­¬­¬¬®­­­­®®­®¬¬­­­­¬­­¬¬¬¬­­­¬­­­¬­¬­­¬¬­­­­­¬­¬¬­¬««««««««««««««¬¬¬¬¬¬­¬­­¬®¬¬¬¬¬­­¬¬­«¬«««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­¬­­®­­­­­­­­­­¬¬­¬¬­¬¬­­¬­¬­­¬­¬¬¬¬­­¬¬¬¬¬¬­­¬¬¬­¬¬¬­­¬­­¬­¬¬­¬­¬¬­­­­¬¬­­­­­­®­¬­­¬¬¬­­­­¬­¬¬­¬­¬¬­­­¬­¬­¬¬­¬­­­¬¬­­®®­­¬«««««««««««««««««««¬¬¬¬¬¬¬¬­­¬­­­®¬­­¬­­¬¬¬¬­¬¬«««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬­­­­­­­­­­­­­­­­­­­¬­¬¬­¬­­­¬­¬¬¬¬¬¬­­¬¬­¬¬¬¬¬­­¬¬¬­­­­¬­­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬­­­­®®­¬­­¬¬¬­­¬­¬­­¬¬¬¬¬¬­­­¬­¬¬­­­¬­­¬­¬®­¬­«««««««««««««««««««««­¬¬¬¬¬­­¬¬¬­¬®®¬¬¬¬¬¬­­¬­¬«¬¬««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­­­­¬­­­­­­­­­­­­¬­­¬­¬­­­­­®­­¬¬­¬­¬¬­¬¬¬­¬¬­¬­­¬¬¬¬­¬¬¬­¬¬­¬­¬¬­¬¬­¬¬¬­¬­­­¬¬¬­­­­¬¬¬¬­¬­­­­®­­­¬¬¬¬¬¬­¬­­­®¬­¬­¬¬­¬¬¬¬¬¬­¬­¬¬­­¬­¬¬¬­­­¬­­­««««««««««««««««««««««««¬¬¬¬¬­­¬¬­­¬¬®­¬­¬¬­­¬­«¬«¬«««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬­¬­­­­¬­­­­­­­­¬­­­­®®®­­­¬­¬­¬­­­¬¬­¬¬¬¬­­¬¬­¬¬­¬¬­¬¬¬¬¬­¬¬­­¬¬­¬¬­¬­¬¬¬­¬­¬¬¬¬¬¬­¬¬­¬­­­­­­­­®®­­­­¬¬­¬­­­¬­¬¬¬¬¬¬¬­¬¬­­­¬¬¬¬¬­¬¬­­¬­¬¬­­¬¬¬¬««««««««««««««««««¬­¬¬¬¬¬¬­¬¬­¬¬­¬­®¬­¬­¬¬¬¬«««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®­­­­­¬­­­­¬¬­­­­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬­­­­­¬¬¬¬¬­­­­­¬­¬­¬­¬¬¬­¬¬­¬¬­­¬¬¬¬¬¬­¬­¬¬¬¬¬¬­¬¬­­­­­­­®®­­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­¬­­­­¬­¬¬¬¬­¬¬­­¬­­­­­««««««««««««««««­¬¬¬­­¬¬­­¬­¬¬­®¬¬¬¬­­¬¬¬¬¬«««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­­­­­­­­­­­­­¬¬­­­­­¬­­¬­¬¬­¬¬¬¬¬­¬¬­­­¬¬­¬¬¬¬¬­¬¬¬¬­¬¬¬­­¬­¬­­¬¬­¬¬¬­¬¬­¬­­­­­­­®®­­­­¬­¬­¬¬¬¬­¬­¬¬­¬­­¬­­­­¬¬­­¬­¬¬¬­¬­¬­­­­«««««««««««««««««««««¬­¬­¬¬¬­¬¬­¬¬­¬¬¬­­¬¬«««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­­­­­¬­­¬¬¬¬­­­­­¬­­­­­­¬¬­¬¬­¬¬­¬¬­­­­­¬­¬¬­­¬­¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬­¬¬¬¬¬­¬­¬­­­­­­­®­­­¬­­­¬¬¬¬¬¬¬­¬­¬¬¬¬­¬­­¬­¬¬­¬¬­¬¬­­­¬­­­­­¬­«««««««««««««««««««««¬­­¬¬¬­­¬­­­­¬¬¬­¬¬««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬­­¬¬¬¬­­­¬¬¬¬¬­­¬¬­­­®­¬­­¬¬­¬¬¬¬¬¬¬¬­­¬¬¬¬­¬¬¬­¬¬¬­¬­­¬¬¬¬¬­¬­¬­¬¬¬­¬¬­¬¬­¬¬¬¬­¬­­­­­­­®®®¬¬¬­¬¬¬¬¬¬­¬¬­¬­¬­¬¬­­¬¬­¬¬¬¬­¬¬¬­¬­¬­¬¬­­¬­««««««««««««««««««««¬¬¬¬­¬¬­¬¬­­®¬­­¬¬­­¬¬­¬««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­­­­­­¬­¬­­¬¬¬­­­­­¬­®¬®¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬­­¬¬¬­­­¬­¬¬­¬¬­¬­¬­­­­¬­¬¬¬¬­­­­­­­­­­­­­¬¬­­¬¬¬¬­­¬¬¬¬­­¬¬­­¬­¬¬­¬­¬¬­¬¬­­­­­­­­«««««««««««««««««««««««¬­¬­¬­¬­­¬­­®¬­®®¬¬­®­­¬¬««««««««««««««««®®®®®­­®®­­­­­­­­­­­­­­¬¬­­­¬­¬­­­¬­¬¬¬­¬¬¬¬¬¬­­¬­­­­­¬­¬¬­¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬­¬­¬­­®®¬­­¬¬­¬¬­¬¬¬¬¬¬¬¬««««­««««««««««««««««««««¬««««««««««««««««¬­¬®®®­¬¬­¬¬­­¬¬«««««««««««««««««®®®®®®®®®­®®®¬­­¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬­¬¬­¬­¬¬¬­¬­¬­¬¬¬¬­¬­¬­­­¬®®¬¬­­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬«««««««¬««¬«««««««««««««««««««««««««««««««¬¬®¬­¬­«««««««««««««««««««««®®®®®®­­­­­­®®®­­­­­­­¬¬¬¬­¬¬­¬­¬¬¬¬­¬¬­­­­­­¬¬­­­­¬­¬¬­¬­¬¬­¬­­¬¬­¬¬¬¬­­­­¬­­­¬­¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬««¬««¬¬««««««««««««««««««««««««««««¬¬­¬¬¬¬¬¬¬¬­¬­¬¬¬­¬«««««««««««««««®®®®®®®®®®­­­­¬¬­¬­¬¬­¬¬¬¬­­¬¬¬­¬­¬¬¬­­¬¬¬­¬­¬¬­¬¬­­¬­¬¬­­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­­­¬¬­¬­¬¬¬­®­¬¬­­­­¬¬¬¬¬¬¬­««¬¬«««««««««««««««««««««««««««««««««««¬¬¬¬­­­­­¬¬¬­­¬«««««««««««««««««««««®®®®®®®®®­­­­®­®®­¬­¬¬¬­­¬­­¬¬­¬­¬­¬­¬¬­¬­¬¬­¬¬­¬¬­­¬¬­¬¬­­­¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬­­¬­¬¬­­¬¬­­¬­­­­¬¬¬­¬¬¬¬¬¬¬¬¬««¬¬¬«««««««««««««««««««««««««««««««««­­¬®­¬­¬¬¬­«¬«««««««««««««««®®®®®®­­®®®­®®®®­­­¬¬¬­­¬¬¬¬­¬­¬¬­¬¬¬­­­­¬­¬¬¬­¬­­¬¬­¬­­­¬­¬­¬¬¬­­¬¬¬­­¬¬­­­­­­¬¬¬­­­¬¬¬¬¬««¬¬¬««««««««««««««««««««««««««««««««««­­®¬¬­¬­­¬««««««««««««®®®®®®®®­­­­­­®®®­­®­­¬¬¬¬­¬¬­­¬¬¬¬¬­¬­¬­¬­­¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬­­­¬¬¬¬¬¬¬¬­¬­­­­¬­­¬­¬¬¬¬­¬¬¬¬¬¬­¬¬¬«««««««««««««««««««««««««««««««««­«­­¬¬®¬¬­¬¬­­«««««««««««««««««««««®®®­­­­­­­®­­­­­­¬­¬­¬¬¬¬¬¬­¬¬­¬¬¬­­­­¬¬­¬­¬¬¬¬¬­­¬­¬¬­¬¬¬¬¬­¬­¬¬­¬­¬­¬­­­­­¬­¬¬¬­¬¬­­¬¬¬¬¬¬«««¬««¬¬­«««««««««««««««««««««¬­¬«««¬¬­¬¬¬¬¬®­¬­­¬««««««««««««««««««®®®®®®®®®®®­­­¬­®­­­­­¬¬­­­¬­­¬¬­¬¬¬­¬¬­¬¬¬­­¬¬¬¬¬¬­¬­­¬­¬¬¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬¬¬­¬­­­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬««­¬«««««««««««««««««««««««««¬¬¬­®¬¬¬¬¬­­¬¬­«¬««««««««««««««®®®®®®®®®­­­­­­­­¬­­­¬­­­¬¬­¬¬­¬¬­­¬¬¬­¬­­¬¬¬­­¬¬¬¬¬­­¬­­­¬­¬¬¬¬­­¬¬¬¬¬¬¬¬­¬¬¬­­¬¬­­¬¬¬¬¬¬¬­¬­¬¬¬«­¬«««««««««««««««««««««««««««««®­­­¬­­¬¬¬¬­¬¬««««««««««««««««««®®®­­­­­­­­­®®®®­­­­­­­­¬­­­­­­­¬¬­¬¬­¬¬­¬­¬¬­­­¬¬­¬¬­¬­­¬­¬¬­¬¬¬­¬¬­­¬­¬¬­¬¬¬­¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬««¬¬¬¬¬«««««««««««««««¬«««««««««««««««¬­¬­¬¬¬¬¬­­¬­¬«¬¬«««««««««««««««««®®®­­­­­­­­­­¬¬­¬¬¬¬¬­­¬­¬­¬¬¬¬­¬¬¬­¬­¬¬­¬¬­­¬­­­¬­¬­¬­¬¬¬­­¬¬¬¬¬¬­­¬¬¬¬¬­¬¬­­­¬¬¬¬«¬«¬¬¬««««««««««««««««««««««««««««««««¬­¬­¬¬­­¬­«¬«¬««««««««««««««««««®®®®®®®­­­­­­­­­­­®®­­­­­­­¬­­¬¬¬¬¬­­¬­­¬­¬­¬¬¬¬¬¬­¬­­­¬­­¬­¬¬¬¬¬­¬¬¬¬¬­¬¬­¬­­­¬¬¬¬¬¬­¬­¬­­¬¬­¬­¬¬­«¬¬¬¬¬¬«¬««««««««««««««««««««««««««­«¬¬¬­®¬­¬­¬¬¬¬««««««««««««««««««««««®®®®®®®®®­­­­­­­­­­­­­­­­­­­¬­­­­­­­¬­­¬¬­¬¬­¬¬­¬¬¬¬­¬­¬¬­¬¬¬¬­¬­¬¬¬­¬¬­¬¬­¬¬­­¬¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬««¬¬«««¬««¬¬««¬«««««««««««««««««««««««¬«¬¬¬¬®¬¬¬¬­­¬¬¬¬¬«««««««««««««««®®®®®®®­­­­®®­­­¬¬­­­¬­¬¬­¬¬­­­¬­¬¬­¬­¬¬­¬­¬¬­¬¬¬¬­­¬­¬¬­¬­­­­­¬¬­¬¬­¬¬­­­¬­­¬¬­¬­¬¬¬­¬¬¬­­¬­¬¬¬¬­¬¬¬¬¬­¬¬««««¬««­««¬««««««««««««««««««««««««¬¬­¬­¬¬¬­­¬¬««««««««««««««««««®®®®®­­­­­­®­­®®®­­­­­­­­¬¬¬­¬­­­¬¬­¬­¬¬­¬¬­¬¬­¬¬¬­­­¬­­­¬¬¬­­­®®®­¬¬¬¬¬­¬¬­­¬­­¬­¬­¬¬¬¬¬¬­¬¬¬¬­¬­¬¬¬¬­¬¬¬¬¬««««««««««««««««««««««««««««««««««­­­¬¬¬­¬¬««««««««««««««««­®­­­­­­­­­®®®®®­­¬¬¬¬­¬¬¬­¬¬¬­¬¬¬¬­­¬¬¬­¬¬¬­­¬¬¬¬¬¬¬¬¬­­­­­­¬­­¬¬­¬¬­¬­¬¬¬­¬¬¬¬¬¬¬­¬¬««««««««««««««¬¬«««««««««««««««¬«««««««««««««¬­­­®­¬­­¬¬­­¬¬­¬«««««««««««««««««««®®®®®­­­­­­­­¬­­®¬­¬¬¬­¬­¬¬¬­¬¬¬¬­¬­¬¬­¬¬¬¬­¬­¬­¬­¬¬¬¬¬­¬¬­¬­¬­¬¬­¬¬­¬®®®¬¬¬¬¬¬¬¬¬¬¬¬¬«¬«««««««««««««¬««««««««««««««««««««««««««««¬«¬¬¬­¬­®¬­¬­¬­®®¬¬­®­­¬¬««««««««««««««««®­­­­­­­®­®®®­­¬¬­¬¬­­¬­¬­¬¬­¬­¬¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬­¬¬­­­­¬¬­­¬­¬¬¬¬¬¬¬­¬®¬¬¬¬¬¬¬¬¬¬¬«­¬¬«¬«««««««««««««««««¬«««««««««««««««««««¬¬­­­®­¬¬®¬¬­¬¬­¬««««««««««««««««««®®­­®­­­­­­®®®­®­¬­¬¬­¬¬­¬­¬­¬­¬­¬­¬¬­¬¬­¬­­¬­¬¬­¬¬¬¬¬¬­¬­¬­¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬«¬«««««««««««««««««««««¬«««««««««««««««««¬««««¬¬­¬­¬®®¬­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬«¬««««««««««««««««­­­­®­­­®­®®¬­¬­¬¬­¬­¬¬¬¬­¬¬­¬¬­¬¬¬­¬­¬¬¬¬­¬­¬¬­¬¬¬¬­¬­­¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬¬¬«¬¬­¬¬¬¬¬¬¬¬¬¬«««««¬««««««««««««««««««««««««««««¬««­¬­­¬¬®¬¬¬­­­¬¬¬­­¬«¬«««««««««««««®­®®­­­­­­­­®®®®­­¬­¬­­¬­¬¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬­­­¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬­­­­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««¬«««««««««««««¬­«««««¬¬®¬­¬¬®¬¬¬¬­­®¬­®®­¬¬­¬¬¬¬¬¬«««««««««««««««««®­­­­­­­®®®®¬¬­­¬­­¬¬­­¬¬¬­¬¬­¬­¬¬¬¬­¬­¬­¬¬¬¬¬­­¬¬­­¬¬¬¬¬¬­¬««««««««««««««««««««««««««««««««««­««««¬¬­¬­¬­®­¬¬¬¬¬®¬¬«««««««««««««««««««««­®­­­­­­®®®®®®®®®¬­¬¬­¬­¬¬¬­¬­¬¬¬¬­¬­¬¬­­­¬¬¬¬¬­¬¬¬­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬«­¬«««««««««««««««««««««««««««««««««««««¬««««¬¬¬¬­®®®¬¬­­­¬­¬­­¬¬¬¬«««««««««««««««««®®®®®®­­­­­­­­­®­¬¬­¬­­¬¬­¬­¬¬­­­¬­­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬­¬­­¬¬¬¬¬­­¬¬¬¬­¬¬¬««««««««««««««««««««««««««««««««««««««««¬¬««¬¬­¬­®®¬­¬­­¬¬­¬­¬­¬¬¬­¬¬¬¬¬¬««««««««««««««®­®®®­­­­­­®®®®®­¬¬¬¬­­¬­­­­­¬­­¬¬¬¬­¬¬­¬­­¬¬­¬¬¬­¬¬¬¬¬¬­­¬¬¬­¬««¬««««««««««««««««««««««««««««««««««««««««¬¬¬­¬¬­¬­­¬­¬¬¬¬¬¬¬««««««««««««««««««««®­­®­­®­­­­®®®¬­¬¬­­­¬¬­¬¬¬¬­¬­­­¬¬¬­­­­¬¬¬¬­¬¬¬¬¬­¬¬­­­¬­¬¬¬¬­¬«¬¬¬¬­«««««««««««««««««««««««««««««««««««­«¬¬­¬­¬¬­­¬­¬¬­­­­­¬­¬¬¬¬«««««««««««««««®­­­­®­­­­­­­­­®­­¬­¬¬­¬¬­¬¬­­¬­­­¬­­¬­­­¬¬¬¬¬¬¬­¬­¬¬­¬­¬¬¬­¬¬¬¬¬¬­¬¬¬¬«««««««««««««««¬««««««««««««««««««¬«­­®®­¬¬­­­­¬¬­­¬­¬¬¬««««««««««««««««®­­­­­­­­­­­­®®®®®¬­­¬­¬­¬¬­­¬¬­¬­¬­¬­­¬­¬¬¬¬¬­¬¬¬¬­¬¬¬­­­¬¬­­¬¬¬¬¬­­­¬¬¬««««««««««««««««««««««««««««««««««««¬¬¬¬¬¬­¬¬¬¬­­¬­¬¬¬­¬¬¬­¬­¬¬¬¬«««««««««««««««««­­­­­­­­­­­­­­­­®®®­­¬¬¬¬¬¬­­¬­­­­¬­­¬¬­­¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­­¬¬¬¬¬¬¬¬¬­¬«¬¬««««««««««««««««««««««««««««««««««¬¬­­­¬¬¬¬­¬¬­¬¬¬­­¬¬­¬­¬¬­­¬«¬¬¬««¬«««««««««««««­­­­­­­­­­­®®­¬­¬¬­¬¬¬¬¬¬­¬­¬¬¬¬­­­¬­¬¬¬¬¬¬¬¬¬­­¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««­­¬¬¬­¬¬­¬­­­­¬­¬¬¬¬¬¬¬¬««««««««««««««««®®®®®­­®­­­­­­­­­®­­¬¬¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬­¬­¬­¬­­¬­­¬­¬¬¬¬­¬¬­¬¬­­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­­¬¬«¬¬­­­¬¬¬­­¬­¬¬¬¬­®­¬¬¬­¬¬««««««««««««««««««««®®®®®­­­­­¬¬¬­­¬¬¬­¬¬­¬¬­¬­­¬¬¬¬¬¬¬¬«¬¬¬««««¬«««««¬«««««««««««««««««««««««««««««««««««¬«««««««««««««««««¬¬¬¬¬¬¬­¬­­¬­¬®­­­¬¬¬¬­­­¬¬¬¬¬«««««««««««««««««««¬®®®®­­®®®®­­®¬­¬¬­­¬­¬¬­¬¬¬¬­­¬¬¬¬««¬«««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬«­­¬­­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬­««««««««««««««««®®®®®®®®®®¬­¬­¬­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬­¬­¬¬¬­¬¬®®­­¬¬¬¬¬¬«­¬¬««¬«««««««««««««®®®®­®®®®­­­¬¬¬­­¬¬¬­¬¬­¬­­¬¬¬¬¬¬¬¬­¬¬¬«««««­«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬­¬¬®¬¬¬­¬¬¬¬­¬«¬­¬¬­«­¬¬««««««««««««®®®®­®­®®­­®®­­­­¬¬­¬¬­¬¬¬¬­­­¬¬¬¬­¬­­­¬¬¬¬¬«­««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬¬¬¬¬­¬¬¬¬®¬¬¬¬­¬­¬¬«¬¬««««««««««««­®­®­­®®®®®­¬­¬­¬¬¬­¬­¬­¬¬­­¬­¬«««¬¬«««««««««««««««««««««««««««««¬««««««««««««««««««««««¬«««««««««««¬¬¬¬­¬­­¬¬®­¬¬¬­¬¬¬¬¬¬¬¬­«««¬«««««««««­««­®­®®®®®®­®­¬¬¬­¬¬­¬¬­­¬¬­¬­­¬¬¬¬««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­¬¬¬¬­¬®¬­¬¬¬­¬¬¬¬«««¬¬¬­«««««««««««««««««®®®®­®®®®­­¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬«««¬­«««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««¬«¬¬¬¬¬¬¬¬®­­¬­¬¬¬¬¬«««¬¬««««««««««««««««®®®®­®­­®®®­­­­­¬­­¬­¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««¬¬­¬¬¬¬¬¬­¬­¬«««­¬««««««««««««««««¬«®®®®®®®®®®®®®­­­­­­­­­­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬«¬«««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««¬«¬«¬¬¬«¬¬­¬­¬¬¬­¬¬«­¬«««««««««««««®®®­®®®®­­­­­­­¬¬­¬¬­¬¬­¬¬¬¬¬¬««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬«¬¬­¬­¬¬¬¬­­®­­¬¬¬¬¬¬¬­¬««««««««««««««««®®®®­­®®­­®­­­­®¬¬­¬­­¬¬¬¬­¬­¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬««««««­­¬¬¬¬¬¬­­¬¬­¬¬¬¬¬¬«¬««¬««««««««««««««««««®®®®®®®®­­®®®­®®®­­­­­­¬­¬¬­¬­­¬­¬­¬¬¬­¬¬­¬¬«««««««««««««««¬«««««««««««««««««««««««««««««««««««««««¬¬­¬­­­­¬­¬¬¬¬¬¬«««««««««««­«««««««­­®®®­®­­®®­®­®­­­­­­­­¬¬¬¬­¬¬¬­¬­­­¬­¬¬¬¬¬¬«««¬««««««««««««««««««««««««««««««««««««««««««««««««««««­­¬«¬¬¬­­®­­¬¬¬¬¬¬¬¬«««««««««««««««««««««««­®®­®®®®­¬­­­­­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬­¬¬­­¬¬¬««««««¬¬««««««««««««««««««««««««««¬«««««««««««««««««««««««­¬¬¬¬¬¬®¬¬¬¬¬¬¬««««¬««««««««««««««««««®®­®®®®®®®®®­­­­­­­­¬­¬¬­¬­­¬­¬¬­¬¬¬¬¬««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«¬¬¬­®®®¬­®¬¬¬«««««««¬««¬«««««««««««««««®®®­®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬­­­«««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««­­¬«­­®­¬¬¬¬¬¬¬«««¬«««¬«««««««««««¬««««««®­®®­®®®®®­®®®®®®®®®®®®®®®®®­­®®®­­­­­¬¬­¬¬­¬¬­¬¬­¬¬¬­¬¬¬«««­¬¬««¬«««««««««««««««««««««««««««««««««««««««««««««««­¬¬¬¬¬«¬­­®®¬­«««««¬««««««««¬«««¬¬««««««®®®­®®®®®®®®®®®®®®®®®®®®®¬­­¬¬­¬®­¬¬­¬¬¬¬«««¬¬«««¬«««««««««¬¬«««««««««««««««««««««««««««««««««««««««¬¬«¬¬¬¬®­¬«««««««««¬««««««««««««¬««««­®®­®®®®®®®®®®®®®®®®®®®®®­®®®­¬­¬­¬¬­¬¬¬¬­­¬¬¬¬«««¬¬««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««­¬­­­¬®®¬¬¬«««««««««¬¬«««««««««««¬«««¬®®®®­®®®®®®®®®®®®®®®®®®®®®®­®®®­­¬¬¬­­¬¬¬¬®­¬¬¬¬¬¬¬¬¬««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­¬¬¬­¬¬­¬®¬¬¬««««««¬«««««««««««««««««««¬®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®­­­­®®®®®­­­®­­­¬­­­­¬¬¬¬­¬¬¬¬¬««¬¬­¬¬«««««««««««¬«««««««««««««««««««««««««««««««««««««««««««««­¬¬¬¬­¬¬¬¬®­¬­««««««««¬«««««««««¬««««®­®®®®®®®®®®®®®®®®®­®­®®®®®­­¬­­­­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬«««¬¬¬««««««««««¬««««««««««««««««««««««««««««««««««««««««««««««««««¬««¬¬¬¬­«­­­¬¬«¬¬««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­¬®¬¬¬¬¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬­¬««¬¬¬««¬«««««««««««««­­¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««­¬¬¬¬¬­¬¬­¬®¬¬¬««««««««««««««««­­¬«­®®®®®®®®®®®®­®®®®®®®®®®®®­®®­­­­¬­®®¬­¬¬¬¬­¬¬¬¬¬¬«­¬¬¬«««««««««««««««¬««««««««««««««««««««««««««««««««««««««««¬¬¬­¬¬­¬¬­­­¬«¬««««««««««««««««¬¬­««««®®®®®®­®®®®®®®®®®®®®®®®®®®®®­®®­­¬®­®®¬¬­¬¬¬¬­¬­¬­¬¬¬¬¬¬«¬¬¬¬««««««««««««««««««««««««««««««««««««­««««««««««««««¬¬¬¬¬¬¬­­¬­¬¬¬­««««««««««««««««««««¬««®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬¬¬­¬¬¬¬«¬¬«««««««««¬«««««««««««««««««««««««««««««««««««««««««««­­­¬¬¬¬­­­¬¬¬¬¬¬««««««««««««««««««¬®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬¬¬­¬¬­¬¬¬«««­¬¬««¬¬«¬««««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««­¬¬­¬¬¬®¬¬«««««««¬¬¬««««««««««­««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®­­¬¬­­¬­¬¬¬¬¬¬«­¬¬­¬««¬««««««¬«¬«««««««««««««««««««««««««««««««««««««««««««¬­¬­¬¬¬¬¬¬¬¬¬¬®¬­«««««««««««¬«««««««««««««­«««®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬­¬¬­­¬­¬¬¬¬¬­¬¬¬«­¬««¬¬««««««««««««¬««««««««««««««««««««««««««««««««««««­­¬¬¬¬¬¬¬¬¬««««««««««««««««««««««®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­­¬¬­¬­¬¬¬¬­­®¬­¬¬¬¬«««««¬­¬¬¬««««««««««««¬¬«««««««««««««««««««««««««««««««««««««««««¬­¬­¬¬¬¬¬««««¬««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®­®®¬­­¬¬­­­­¬­­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬««««¬«««««««««««««««««««¬««««««««««««««««««««««««««««««««««««­¬¬­­¬¬­¬­®¬««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®­¬­­­­­¬¬¬­­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­««­«««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«¬­¬«®««««««««««««««««¬««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬­¬­¬­¬­­¬¬¬­¬­¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬««¬««««««¬««««««««««««««««««««««««««««««««««««««««­«¬­­¬««««««««««««««««««««««¬««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­¬¬­¬¬­¬¬­¬­­­¬¬­­¬­¬¬­¬¬¬¬«¬¬¬¬¬¬¬««¬«««¬«««««««««¬««««««««««««««««««««««««««««««««««««««««¬«¬¬¬««««««««««««««««««««««¬««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­¬­¬¬­¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬«¬¬¬­¬«¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬««­«««««««««««««««««««««¬¬¬«««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­¬¬­­¬­­¬­¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬«­«««««««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­¬¬¬­­¬­¬¬¬­¬¬­¬¬¬®¬¬¬¬¬¬¬«««««««¬«««««««««««««««««««««««««««««««««««««««««««««««¬¬««®¬­««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­¬¬¬¬¬¬­¬¬­­¬­¬­¬¬®®®¬¬¬¬¬«¬¬­¬¬¬¬­¬««¬«««««««««««««««««««««««««««««««««««««««««««««««¬«¬«¬­¬¬««­¬«««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬­¬­¬¬­¬¬­­¬¬¬­­®®®­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬­««®¬«««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®­­­­¬¬¬­¬­­­¬­¬­­­¬®®®­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­­¬¬¬«®««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬¬­¬¬­¬¬¬­¬¬­­¬¬®¬­¬¬­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««««¬«««­¬¬¬¬««¬­«««««««¬««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­®­­¬­­¬¬­­¬­¬­¬¬­¬­­¬¬¬¬­¬¬¬­¬¬­­­¬¬¬¬¬«¬««««««­««««««««««««««¬««««««««««««««««««««««««««««««««««««««««­­««®¬«««««««««¬«««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­¬¬­¬¬­¬¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬­¬¬«¬¬¬¬««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­­­¬¬­¬­¬­¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬«¬«¬­«««««¬««««««««««««««««««««««««««««««««««­««««««««««¬¬­¬¬¬¬­««««­­¬¬«««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­­¬­¬­­¬­¬¬­­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬«««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬¬¬¬«®¬­««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬¬¬¬¬¬­­¬¬¬­¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬«¬««««¬««¬«¬­«««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬­¬­««­®­¬¬««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬®®¬­¬¬­«¬¬¬¬¬¬­­­¬¬¬¬¬­¬««««««¬«««¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬­¬¬««®¬¬¬¬««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬¬¬¬¬­­­­¬­¬®­¬­¬­¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬­®¬¬¬­¬¬«««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­«««¬®¬¬««««¬««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­­­¬­­­­¬­¬¬¬¬®®¬¬­­¬¬¬¬­¬¬¬¬¬­­¬¬¬¬­¬­¬­««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«««««««««««««¬««­­««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬­¬¬­¬¬­¬¬­¬­­®¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­¬¬¬­­¬¬­¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬®­¬­¬¬«««««««««¬«««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­¬¬¬­­¬­­¬¬¬­¬®®®¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­­­¬­¬¬¬­¬­¬«¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬®¬¬««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬­¬­¬­¬­­­¬­­­¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬­¬¬­¬­¬¬­¬«««««¬«««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬®¬¬¬¬«««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬­¬¬­¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬­­­­­­¬¬¬­­­¬­¬­¬¬¬¬«««««««««¬«««««««««««««««««««««««««««««««««­«««¬«««««««««««««««¬¬­®¬­¬«¬«««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­¬­­­­­¬¬­¬¬­¬­¬¬­¬¬¬­¬¬­­­­¬­­­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­­¬«««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬¬¬¬­¬­­¬­­­­¬¬¬­¬¬¬­­¬¬­­¬¬¬­¬¬­­¬¬¬¬¬­¬¬««««¬««««««««««««««««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««­­¬¬¬¬««««««««««««««««««¬«®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬­¬­¬¬­­¬¬­¬¬­¬¬­­¬¬¬­¬¬­¬¬¬¬¬­¬­­¬¬¬¬­¬¬­­¬¬­¬­¬««««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««¬¬¬®¬«««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­¬­­¬­¬¬­¬¬­¬¬­­­¬¬­¬¬¬¬­¬¬¬¬­­¬¬¬¬­¬¬­¬¬¬¬¬¬­¬­­¬­­¬««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬««««­­­¬««««««««««««««««««««««««««®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­®­­­¬¬­¬¬­¬¬­¬¬¬­¬¬­¬­¬¬­¬­­¬¬­­¬­¬¬¬¬­­­¬­¬¬­­­­­¬¬¬««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««¬¬«¬««­¬«««««««««««««««««««««««®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬­¬­¬¬­¬¬­¬­¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬­­¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬««««««««««««««««¬««««««««««««««««««««««««««««««««««««««¬«­¬­«««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬¬­­¬¬­¬­¬­¬¬­­­¬¬­­¬­¬¬¬­­­¬­¬¬¬¬­­­¬­­­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««­«««««««««««««««««««¬««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬¬­­­¬¬­¬¬­­¬¬­¬¬¬¬­¬¬¬­¬¬¬­¬¬­¬­¬¬¬¬¬­¬­¬¬­¬­¬¬­¬­­¬­­­¬¬««««««««««««««««««««««««««««««««««««««««««««««««««¬¬­¬««««««««««««««««¬««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­¬­¬¬­­­¬­¬¬­¬¬­­®­¬¬¬­­¬¬¬­¬¬­¬­¬¬¬­­¬¬¬­¬¬¬¬¬¬«¬««««««««««««««««««««¬«««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­­¬¬­¬­­¬­¬¬­­¬¬¬­¬­¬­¬¬­­¬­¬¬­¬¬¬¬­­¬­¬­¬¬¬¬­¬¬­­¬¬¬¬««¬«««««««««««««««««««««««««««««««««««««««««««««««¬««««««««««««¬«««­­««¬««««««««««««««««««¬«««¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬­­­­¬¬¬¬­¬¬­¬¬®¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬­¬¬¬«««««««««««««««­«««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬­«¬««««««««««««««««««««««¬¬­¬¬¬¿¿¿1¿1¿¿¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­­­­­­­¬¬¬¬¬¬­¬­¬¬¬¬­¬¬­­¬­¬­¬¬­¬¬¬¬¬­¬¬­­¬­¬¬¬¬­¬¬­¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««®¬««¬«««««¬««««««««««««««««­¬¿1¿11¿1¿11¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­®­­¬¬¬­¬­¬¬¬¬¬¬­¬¬¬¬®®®¬­¬¬¬­¬¬­¬¬¬¬¬¬­¬­¬¬¬¬¬¬­­«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­¬¬¬««««««««««¬«««««««««««¬¿¿1¿¿¿11¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬¬­­¬­­­­­¬¬­¬­¬­­¬­¬­­¬­¬¬­¬¬¬¬­­¬¬­¬¬¬«¬«««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««««««««««««««««««­«¬«««««««««««««««««««««««««««¬¬«¬1¿¿1¿¿1¿¿11¿¿¿1¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®­­­¬¬­¬¬¬­­¬¬­­¬¬¬­®­­¬¬­¬­¬¬­¬­¬¬­¬¬¬¬¬¬­¬­¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­««««««««««««««­¬¬«««««««««­¬¬¬¬¿¿11¿¿¿1111¿¿¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­¬¬­­­¬¬¬¬¬¬­¬¬­¬­¬­¬¬¬¬­¬¬­­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬««««««««««««««««««««¬«««««««««««««««¬««««««««««««««««««««««««««««««««««««««««­¬«««««««««««««¬¬­««««««¬1111111¿¿1¿11¿¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­¬­¬­¬¬¬­­¬¬¬¬­¬¬­¬­¬¬¬¬­¬­¬¬¬¬¬¬­¬­¬¬¬««««««««««««««««««««««««««««««««¬««««««««««««««¬«««¬«««««««««««««««««­¬­««««««««««««­«««¬¬¿¿111111¿¿11¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­­¬­­­­­­¬¬¬¬¬­¬¬­¬¬¬¬­¬­¬­¬¬¬­­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬«¬««««««««««««««««««¬¬¬¬¬¬¿¿11¿1¿¿¿1¿1¿11¿¿1¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­¬­­¬¬¬¬­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­­­¬­­¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««­«««««««««««««««««««««««««««««««««««¬¬«««««««¬«««««««««¬«««««««««¬¬¬­¬¿¿¿1111¿1¿¿¿¿11111111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬¬­¬¬­¬­¬¬­¬­¬¬­¬­¬¬­¬¬­¬­¬¬¬¬¬¬­¬¬¬­­­¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««««­¬¬««««««««««««««««««««¬¬«¬¬­¬¬«111¿¿11111¿1¿¿11111111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­®­¬¬­­®¬­¬¬¬­¬¬®­¬¬­­¬¬­¬¬­¬­¬¬­­¬¬­¬¬¬­¬¬­¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬«««««««««««««««««««««««­¬«1¿¿11¿11111111¿¿1111¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬­¬¬­¬¬¬¬­¬¬­­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬««¬««««««««««««««««««««««««««««««««««««««««««¬««««««««­««««««««««««««««««¬¬¬«««««««««««¬«¬«««««««¬¿¿1¿1111¿¿11¿¿1¿1111111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­¬­¬¬­¬¬¬­¬­¬¬­¬¬­¬¬¬­¬­¬­¬­¬¬­¬¬¬­­¬¬­¬­¬­­¬¬¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬«««««««¬««««««««««­¬¬1¿¿1¿¿1¿¿1¿111¿11111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­­¬¬¬¬¬®­­­¬¬­¬¬­¬­¬¬­­­¬¬¬¬¬­­¬¬¬­­¬­¬¬¬¬¬¬¬¬­¬¬¬­«¬¬¬«¬«««««««««««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««¬­«¬¬«««««««««««¬«««­«««««««¬¬¬­¬«¿¿¿11¿1¿¿111¿1111¿¿1¿¿¿1¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬­¬¬­¬¬­¬¬­­¬¬­¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬«¬¬«««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««¬¬««««««««««¬«««««««­¬¬¬«1¿1111¿¿1¿1111¿¿¿¿¿¿1¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­®®­­¬¬­¬¬­­¬­¬¬­¬¬­¬¬¬¬¬­­­®¬¬¬¬¬­­­­¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬­­¬«««««««««««««««««««««««¬¬¬¬¬¬¿¿¿¿¿¿¿¿¿¿111¿¿¿1¿1¿¿1¿¿¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®¬­­¬¬¬®®¬¬¬¬­¬¬­¬¬­­¬¬¬¬­¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬­¬­¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬­¬««««««««««««««¬««««¬¬¬¬1¿¿¿¿¿¿1¿11¿11¿¿11¿1¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­¬­­¬¬­­­¬­¬¬­¬¬¬¬¬­¬¬¬¬¬­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««««¬««««««««««««««««««««««««««««««««««¬¬¬¬¬¬¬«««««««««««««««¬¬¬¬«­¬¬¬¿¿¿¿¿¿11¿11¿¿¿1¿1¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®­­®®­¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬­­¬­¬¬¬­­¬­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬«¬«««««««««¬¬¬¬¬¬­¬¬¿¿111¿¿¿¿¿¿¿1¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­®­¬¬¬­­­¬¬­­¬¬­¬¬­¬¬­¬­¬¬­­¬¬­­¬¬¬¬¬¬­­¬¬­«¬«««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««¬¬««««««««««««««««««««««¬­¬««««««¬«««««­«¬¬¿1¿¿1¿¿¿11¿¿11¿¿1¿¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬­¬­¬¬­¬¬¬¬¬¬¬­¬¬¬­¬­¬¬­¬­­­¬­­¬¬¬¬¬¬¬¬­¬¬««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«««¬­¬¬¬¬¬¬««««««««««¬¬¬¬¬¿¿¿¿¿1¿¿¿¿¿1¿¿1¿¿1¿¿1¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬­­­¬¬­¬¬¬­¬­­­®­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬¬¬««««««««¬¬­¬«­«¬­¬¬¬­¬¿¿¿¿¿¿¿11¿¿¿1¿¿1¿¿¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­­­¬®¬¬¬­­¬¬­­­¬¬­¬­­¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬¬¬¬¬¬¬¬«««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬««««¬¬««««««««¬­««««¬¬¬¬¬¬¬¿¿¿¿11¿¿¿¿11¿¿¿¿1111¿111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬®­­¬­¬­­¬¬¬­¬¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬«««¬¬¬«««««¬¬««¬¬¬¬¬¬¬¬«¿¿111¿¿1111¿¿¿¿¿1¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®­®®®¬­­¬¬­¬¬¬¬­¬¬¬¬­­¬­¬¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬««««««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««­¬¬««¬¬­¬¬¬«««««¬««¬¬¬¬¬¬¿111¿¿¿¿¿¿¿¿¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®­®­­¬­­­­¬­¬¬­¬­¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«­¬¬¬¬«««««««««¬¬««««¬««¬¬¬¬¬¬¬1111¿¿¿¿¿¿111¿¿¿11¿®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬­¬¬¬­¬­¬¬­¬­¬¬¬¬¬¬­­¬¬­¬¬¬¬¬­¬¬¬«««¬««««««««««««««««««««««««¬««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««¬¬­­¬­««««««««««««««­¬¬¬¬¬¬¬¿1111¿¿¿¿¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­­¬­­¬­¬¬­­¬¬­­¬¬­¬¬­­¬¬¬¬¬¬¬¬­¬¬¬««««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««¬­¬¬­«««««««««««¬¬¬¬¬¬¬¬­¬111¿¿¿11¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®­­­­­­¬­­¬¬¬­¬­­¬¬¬¬¬­­¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««¬««««««««««««««««««««««««««««««««««««««««¬«««««««««««««««««««««««««««««««««««««««««««¬¬¬¬¬­¬¬««««¬«««¬«««««¬¬¬­¬¬¬­¬¿¿11¿¿¿111¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬­¬¬¬¬­­­¬¬¬¬¬¬¬¬¬­¬¬­­­­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««««««««««««««««««¬«««««««««««««««¬«««««««««««««««««««««««««««««««¬««¬¬¬¬¬¬¬««««««««««««¬¬¬¬¬¬¬¬­¬¬¬¿¿11¿¿¿¿11¿¿11¿¿1¿¿¿®®®®®®®®®®®®®®®®®®­®®­®®­¬¬¬¬­¬­­¬¬¬­¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬«««¬«««¬¬««««««««««««««««««««««««««««««««««««««««««««««««««««­««««««««««¬«««««««««««¬¬¬¬¬­­¬««««««««««««««««¬¬¬¬¬¬¬­¬¿11¿¿¿¿¿1¿1111¿¿¿¿¿¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬¬­¬­¬­¬­­¬¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬««««««¬«««««««««««««««««««««««««««««««««««««««««««««««««««««­«««««««««««««««««««««««««««««««««««««««¬¬¬­¬¬¬­­¬¬««««««««««««««««««¬¬­¬¬­¬¬¬¬¬­¬1¿¿¿11¿¿¿¿1¿111¿¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­­­­¬¬­­¬¬­¬¬­¬­¬¬¬¬­­¬­¬¬¬­¬­¬­¬¬¬¬¬¬­¬­¬­¬¬¬¬«¬«««««««««««««¬¬¬¬«««««««««¬¬­¬¬¬¬««««««««««««««««««««««««««¬««¬««««««««««««««­¬¬¬­¬¬««««««««««¬­¬¬­­¬¬«1¿¿¿111¿11¿11¿111¿®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬¬¬­­¬¬¬¬­¬­¬­­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬«¬¬«««««««««««««««««««¬««««««««­«««««««¬«¬¬¬¬«««««««««««««««««««««««««««««««««««««««««««««««««­­¬­¬¬««««««««¬¬¬¬¬¬­­¬¬1¿¿¿11¿¿¿111¿11¿11¿¿1¿¿¿¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬­­­¬¬¬­¬¬¬­¬­¬¬­¬¬¬¬¬¬¬®­­¬­¬­¬¬¬¬¬¬¬«¬«««««««««««««««««««««««¬¬«¬¬¬¬«««««««««««««¬­¬¬¬¬««««««««««««««««««««««««««««­«««««««««««««¬¬¬­¬­««««¬­¬¬­¬¬¬¬¬¬1¿¿¿¿¿¿111¿11111111¿¿¿¿¿¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬­¬­¬¬¬¬¬­¬­­­¬¬¬¬­¬¬­¬¬­¬¬¬¬­¬­¬¬¬¬­¬­¬¬¬«­««««««««««««««««««««¬«««««««««««¬­­¬¬¬­¬««««««¬«««««««««««««««««««««««««««««««­¬««««¬«¬¬¬­¬¬¬¬¬¬1¿¿1¿¿¿¿¿¿11¿1111¿¿1¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­¬­­­­¬­­¬¬¬¬¬­¬¬¬­¬­¬¬­­¬­¬­­­­¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬«¬«««««««««««««««««¬¬««¬¬¬¬¬««««««««­­¬¬¬­­«¬««««««««««««««««««««««««««««¬«¬«¬«««««¬«««««««¬«¬­«¬«««««¬¬¬¬¬¬¬­¬¬¬1¿¿¿1¿1¿1¿111¿¿¿1¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®®­­­­­¬¬­¬¬­­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­­¬¬¬¬­¬­¬¬­¬­­¬¬¬¬¬¬«««««««««««««¬¬¬¬¬¬««««««««¬¬¬­¬­­««¬¬««««««««««««««««««««««««««««««¬¬¬««««««««««­«¬­««««««¬¬«­¬¬¬¬¬11¿1¿11¿¿1¿¿¿1¿1¿¿11111¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­­¬¬­¬­­­¬­­¬¬¬¬¬¬­­­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­­®¬¬­­¬­¬¬¬¬«««¬¬««««««««¬««¬«¬­¬««««««««««¬­­¬­¬­¬«««¬««««««««««««««¬«¬«««¬«««««««««««««««¬¬¬«««¬¬¬¬¬¬11111111¿¿1¿1¿¿11¿¿¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­­­­¬­­­¬­¬­¬­¬¬­¬¬¬­¬¬¬¬¬­¬­¬­¬­®­¬­­¬¬­««««­««««««««««««««««¬¬¬¬««««««¬«¬¬¬¬««««««««««««««««««««««¬¬¬¬«««««««««««««««««¬¬«­«¬¬¬«¬¬¬¬¬¬¬­1111111111¿¿111111¿11¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬­¬­¬¬¬¬­¬­¬¬­¬¬¬­¬¬­­­¬¬¬«««««««««««««««««««««««««««­«­­¬¬««««««««««¬¬«««««««««««««««««««««¬«««««««««««««««¬¬®¬¬¬««««­¬¬¬¬«111111111¿11¿¿111¿111¿1¿®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬­­¬¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­­¬¬­¬­¬¬­¬­¬¬­¬­¬¬««««««««««««««««¬¬¬¬¬«¬¬¬¬¬««««««««««¬¬¬¬««««««««««««««««««««¬««««««««««««««««««¬¬¬««««««­¬¬¬¬­¬¬111111111111¿¿¿¿¿¿¿1¿1®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬¬¬¬¬¬­­¬¬¬­¬¬­­¬­¬­¬¬¬­¬­¬¬¬­¬¬­­­¬¬¬­¬­­¬¬­­¬¬¬¬¬­««««««««««««««­­­«¬¬««««««««««««««¬­«¬««¬¬««««««««««««««««¬««««««««««««««««­««««««««¬¬¬¬¿111¿1111¿¿¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®¬­­®­¬¬­¬­­­¬¬­¬¬¬­¬¬¬¬­­¬­¬¬¬¬¬¬¬­­¬­­¬¬­­¬­­­¬¬¬­««««««««¬«««««¬¬¬¬¬¬­¬¬««««««««««««¬¬«««¬««««««««««««««¬««««««««««««««««««¬¬«««««««««¬¬¬¬¬­«¿111111¿¿¿¿¿¿¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬­­¬­¬¬¬¬¬­¬¬­­­¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬«««««««««««¬¬¬¬¬­¬¬­­¬««««««¬««¬¬­­¬­­¬««««««««««««««««««««««««««««««««««««««««««­¬¬««««««««¬«¬¬¬¬11111111¿¿¿11111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®­­­¬­­­¬¬¬¬­¬¬¬­¬¬­¬¬¬¬­¬­¬¬¬­­¬­¬­¬­¬­­¬­¬­¬¬¬¬¬¬­«¬¬««««««««««««««¬­¬¬¬¬«««¬¬««¬¬¬¬««««¬«¬««««««««««««­««««««««««««««««««««««««¬¬¬«««««««««¬¬¿1111111¿¿11111®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®­­­­¬¬­­­­­­­¬¬¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬¬­¬¬¬­­¬­¬¬¬¬­­­¬¬¬¬­¬«««««««««««««««««¬«¬­¬¬¬¬««««««««««­¬¬¬«¬­­¬«¬¬««««««­««««««¬¬«««¬«««««««««««««««¬¬­¬«««««««««¬««¬¬¬¬¬¬¬11111111¿¿¿¿¿¿¿¿1111¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬¬¬¬­¬¬­¬­¬¬­­¬­¬¬­¬¬­¬¬¬¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬««««««««¬«««««««««¬¬­­¬¬¬¬«««««««¬­¬­­«¬«¬«««««««««««««««¬«««««¬««««««««««««««­­««««««««««««¬¬1111111¿11¿¿¿¿¿®®®®®®®®®®®®®®®®­®®®®®®®®®®®®­¬­­­­¬­­­­­¬¬¬¬¬¬¬®­­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬««««««¬¬¬­¬¬«¬«««««««¬¬­«¬­¬«««««««««««««¬«««««««««««««««¬«­¬¬¬«««««««««««««¬¬«¬¬1111111¿¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®­®®®®®®­­¬¬­¬¬­¬­¬­¬­¬¬¬­¬­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬¬¬«¬¬¬¬¬¬¬¬«««««¬««««¬­¬««¬¬¬¬«««««««¬­««¬«««««««««««««««««««««¬­¬¬¬¬«««««««¬¬¬¬­11111111¿11¿11¿®®®®®®­®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬®­­­­¬¬­­¬¬¬¬­¬­¬¬¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬««¬««¬¬¬¬¬¬¬­¬««««««¬¬¬¬¬««¬¬«««««««­¬««««««««««««««««««««««««««­¬¬¬¬­««««­¬¬¬¬¬¬­11111111¿11¿11¿1®¿®®®­®®®®®®®®®®®®­®®®®®®®®®®®®®®®­®­®®­­¬­­­¬¬¬­¬¬¬­¬¬­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬««¬«¬¬¬­­¬¬¬¬¬«««¬««««««««¬¬«««­««¬«««««««««««««¬«««««««««««««««««««­¬¬¬¬«««««««¬¬¬¬¬¬¬¬¬111111111111¿¿11¿®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­¬¬¬¬­¬¬­¬­¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬­¬¬««««««««««¬«¬­¬¬««««««««««««««««««««««««««««««¬¬¬¬¬¬«««««««««««¬¬¬¬¬¬¬¬¬11¿11111111111¿1¿¿®®®¿®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬­­¬¬¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬¬­¬­¬­¬¬¬¬­­­¬¬¬¬­¬¬¬¬­­¬¬­­­«¬¬­¬¬¬¬­¬¬¬«««««««««««««­¬«««¬¬¬¬««««««««¬«««««¬««««««««««««¬¬¬¬¬¬««««««««««««««¬¬¬¬¬¬¬1111111111¿¿1¿¿¿®®®®®­®®®®®®®®®®®®­­®®®®®®®®®®®­¬¬­­¬¬¬¬¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬«¬¬¬¬¬¬¬¬¬««««««««««««­««­¬««¬«««««««««««««««««««««««««««««¬­¬­¬¬­­¬­«««««««««««¬¬¬¬¿1111111111¿¿¿¿¿®®®®®®®®®®®®®­®®®®®®®®­®®®®¬¬¬­¬­­¬¬¬­¬¬­¬¬¬¬­­®­­¬¬­­¬¬­­¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬««­¬¬¬¬¬¬­¬­¬¬«««««««¬««««««¬¬««««««««««¬««««««««««««««««««¬¬¬¬¬­¬­¬¬¬«««««««««¬¬¬¬¬¬¬¬¬¬11111111111¿¿¿¿1¿¿¿¿®®®®®®®®­­®®­®­­®®®­®®®®®®®®®®®­­¬¬­¬­¬¬¬­¬¬¬¬­¬¬¬­­¬­­­­¬­¬¬­¬­¬¬¬¬­­¬¬¬­¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬«¬¬¬¬¬¬¬­­¬¬¬¬«««««««««««¬¬¬«««««­¬«««««­«««««««««««««««««««««¬¬¬­¬¬«««««««««««¬¬¬¬1111111111¿¿1¿¿¿11¿¿¿®®®®®®®®®­®®®®­®®­®®­­®­®®­®®®®®®®®®­¬¬­­­¬¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬««««¬¬¬¬¬¬­««««««««¬¬««¬¬¬¬¬««¬«¬¬«««««««««««­«««««««««««««««««««¬¬¬¬¬¬¬«««««««««««««««««¬¬­«¬¿11111111¿1¿¿¿¿¿¿¿®®®®®®®®®®®®­®­®®®­­®®®®®®­­­®¬­­¬¬¬¬¬¬­¬¬¬¬¬­¬­¬¬­¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬¬««««¬¬¬¬¬¬¬¬««««««««««««««­¬¬««««¬¬¬¬¬«««««««««««««««««««««««««««««««¬­¬¬¬¬­««««««««««««««¬¬¿111111111¿¿1¿¿¿®®®®®®®­®®­®®®®®®®­®®®®®®­¬­­­¬¬¬­¬¬¬¬­­¬¬­¬¬­¬¬­¬¬¬­¬­­­¬­¬­¬¬¬­¬¬¬¬¬¬«««¬¬«¬¬¬¬¬¬««««««««««««¬¬¬«««««­«««««¬«««««««««««««««««««««¬¬¬¬¬­¬¬«««««««««««««««¬¬¬1111¿11111¿¿¿¿¿¿¿®®®®®®®®­®­®®®®­®®®®®®®®®®®­­­®¬¬¬¬¬¬­¬¬¬¬­¬¬­­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬«¬¬¬¬¬««««««««««¬««¬¬«¬«««««««««««««««««««««««««««¬«¬¬­®¬¬¬­­¬¬¬«««««««««««¬¬¬¬¬«1¿1¿¿111¿¿¿1¿¿1¿¿®®®®®®®®®®®®®®­®®­®®­®®­­¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬­¬¬­¬­¬¬­¬­­­¬¬­¬¬­¬¬¬¬¬­­­¬¬¬¬¬¬«««¬¬¬¬¬­¬¬¬¬¬¬¬«¬«««««««««««¬¬««­¬¬«¬««¬««««««««««««««¬«««««««¬¬­¬¬¬«««««««««««««««¬¬¬¬¬¿1¿¿¿¿¿¿¿¿¿¿¿®®®®­®®®®®®®®®®­®­­®®®®®®®®­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬­­¬¬¬­¬­­¬¬¬­­­­­­¬¬¬¬¬¬¬¬¬¬¬¬««««¬¬­¬­­¬¬­«««¬¬««¬«««¬¬¬¬­««««««««««««««««««««««««««««¬¬¬¬­¬¬¬¬­¬«««««««««¬¬¬¬¬¬¬¬111¿¿1¿¿¿1111¿11®®®®®­®®®®®®®®®®­®®®®®®®®®®®­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬¬­­­¬¬­¬¬¬¬¬¬¬¬«¬¬¬¬¬­¬«««««««¬««­¬¬«¬­¬««««««««««««««««««««««««««««««¬­­¬¬­¬««««««««««««««¬­¬¬11¿¿11¿11¿¿11¿1¿¿¿¿¿¿¿®®­®­­­®­®­­­­­­­­­­­®®®­®­®®®®­¬¬­¬¬­­­¬­¬­¬¬¬¬­­¬¬­¬¬­¬¬­­¬¬­¬¬­¬¬¬­¬­¬­¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«¬«¬«¬¬¬¬¬¬¬¬¬¬¬­¬¬««««««««««««««««««¬­¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬111111¿11¿¿¿¿1¿111¿¿¿¿®®­­®­­­­­­­­­­­­­­­­®®®­®®®®®­­­­¬¬¬¬¬¬¬­¬¬¬¬­¬­­¬¬­¬­­¬­¬¬¬¬­¬¬­¬¬¬­¬¬­¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬«¬¬¬¬¬­¬¬¬¬¬¬¬««««¬«««¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««¬¬­­¬­¬¬¬­¬­­­¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬1111111111¿¿11¿11¿¿¿®®­®®­­­­­®­­­­­­­­­­®®®®®®¬®­­¬¬­¬­­¬­¬¬¬­¬¬­¬­¬¬­¬­¬­¬­¬­¬¬­¬¬­­¬¬­¬­¬­¬¬¬¬­­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬«««¬««««««««¬¬¬¬­¬¬­­¬¬­­¬¬¬¬«««««««««««««««««««««««««««««¬¬¬­¬¬­¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¿1111111¿¿111¿1¿¿¿®­®­­®­­­­­­­­­­­­­­­­­­®®®®¬­­¬­­¬­¬¬¬¬¬­­¬¬­­¬¬¬­¬¬­¬­¬­¬¬­¬¬­¬­¬­­­¬­¬­­¬­­¬­¬¬¬­¬¬­¬¬­¬¬¬¬¬­¬«¬¬¬¬¬¬¬¬¬¬¬«««««««¬¬­««¬¬¬¬¬¬¬¬¬¬­­¬«««««««««««««««««««««««««««««««¬­¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬111111¿¿1111¿¿¿¿¿¿®®®®®­­­­­­®­­­­­­­­­­­®®­®®®®¬¬­­­­­¬­­¬­¬¬­­¬¬­­­¬­¬¬¬¬­¬¬¬¬¬¬¬­¬¬­­­­¬­¬¬¬­¬¬¬¬­­¬¬­¬¬¬­¬­¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬««««««¬«««««¬««¬¬­¬­­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬1111¿¿¿1¿11¿¿1¿111¿¿®®®­­­­®­­­­­­­­­­­®­®®­®®®®®®®¬­¬¬­­¬­¬­­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬­¬­¬¬­­­¬­¬­¬¬¬­¬­¬¬­­¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬«¬¬¬¬¬¬¬¬¬¬««««««««««««««««¬«««¬¬¬¬¬¬¬¬­¬¬¬¬¬¬««««««««««««««««««««««««««««««««««¬¬­¬¬­¬­¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬1111¿1¿¿1111¿¿1¿111¿¿¿1®¿®®­­­­­®­®®­®­­­­­­­­­®­­­­®­­®­­¬¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬­¬­¬¬­¬¬­¬­¬­­¬¬­¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­«¬¬¬¬¬¬¬¬¬¬¬««¬«««¬««««¬¬­¬¬¬¬¬¬¬««««««««««««««««««««««««««««««««¬¬¬­­­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬111111¿¿11¿¿1¿1¿¿¿¿¿¿¿1®¿®®®®®®®­­­­®­­®­­­­­­­­­­­­®­®®­¬­­­¬¬¬­¬­¬¬­¬¬­¬­¬­¬¬¬­­¬¬­­¬­¬¬­­­¬­¬¬­¬­­¬¬­¬¬­¬­¬¬­¬¬¬¬­¬­¬¬¬¬­¬«««¬¬¬¬¬¬«««««««¬««««¬¬¬¬¬¬¬­¬¬¬¬¬«««««««««««««««««««««««««««««««¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬11¿1¿111111¿¿¿1¿1¿¿®®®®®®®­­­­­®®­­­­­­®­®®­®­­®­¬­­¬¬¬¬­¬¬­¬¬­¬­­­¬­­¬¬¬­­¬­¬­¬­¬¬­¬­¬­¬¬­¬­¬­­­­­¬¬¬¬­¬¬¬¬¬¬¬¬«¬¬¬¬¬«««««««««««««­¬¬¬¬¬­¬¬¬¬¬¬¬«««««««««««««««««««««««««««­¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¿1¿1¿11¿1111¿¿¿¿¿¿®¿¿1¿®®®®®®­­­­­­­®­­­­­­­­­­®­®­®­®®®®­­¬¬­­­¬¬­¬­¬¬­¬¬­¬¬¬­¬¬­­­¬¬­¬­¬¬­­¬¬­­¬¬­¬¬­¬¬¬­­­¬¬¬­­­­«¬«¬¬¬¬¬¬¬¬­¬¬¬¬«¬«««¬«««¬«««¬««­¬­­­¬¬¬¬¬­¬«¬««««««««««««««««««««««««««««­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¿1¿11111111¿¿¿¿¿®®¿®®®®®®­­­­­­­­®­­­­­­­­®­®®­®®®®®®­­­¬¬­­­¬­¬­­®¬­­¬¬¬­¬­¬¬­¬¬­­¬¬¬¬¬¬¬¬­¬¬­­¬¬­¬­¬¬­¬­¬¬­­®­­¬­¬®®¬­¬¬¬¬«¬¬¬¬¬¬¬­¬¬¬««««¬««¬««¬­­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬««««««««««««««««««««««««««¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬­­­¬¬­¬¬¬¿¿1111111111111¿111®®®®®®­­­­®­­­­­­®®®®®®®®®®­­­­­¬­¬¬¬­¬¬­­­­­­­¬­¬¬¬­¬­­¬­­­­¬¬­­­­¬¬¬­¬¬­¬­­­¬¬­¬­¬¬®¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««««««««­¬¬«¬¬¬¬¬¬¬­¬¬¬¬¬¬«««««««««««««««««««««««««««®¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­­¬¬¬11111111111111¿¿¿1¿®®®®®®®®­­­­­­­­­­­­­­­­­®­®®­­®®®®®­­­¬­­¬¬¬¬­¬­¬¬¬¬­¬­¬¬­­­­¬¬¬¬¬­¬­­¬¬­¬­¬¬¬­­¬¬­­¬­­¬¬¬­¬¬­­¬­¬¬¬¬­­¬¬¬¬¬­¬¬¬¬¬«««««««««««¬¬«¬¬¬­¬­­­­¬«««««««««««««««««««««««««««««««««­­¬¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¿111111111111¿¿¿¿11¿®®®®®®®®®®®­­­­­­­­­­­­­­­­­®®®­­­­®®®­­­¬¬­¬¬­¬¬¬¬­¬­¬¬­¬¬­­¬¬¬¬­¬¬­¬­¬­¬¬­¬¬­¬¬­¬¬­¬­¬­¬­¬¬­­¬­¬­¬¬¬­¬¬¬¬­­¬¬¬¬¬¬«¬¬¬¬¬¬¬¬«««««««««««¬¬¬¬¬¬¬¬¬¬¬¬­­«««««««««««««««««««««««¬«¬¬¬­­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬1111111111¿111¿1¿1¿¿1®®®®®®®®®®®­­­­­­­­­­­­­­®­­®®®®®®­®®®®®­¬¬¬¬­¬¬­¬­¬­¬¬¬­¬¬­¬­­­¬¬¬¬¬¬¬­¬¬¬­¬­¬­­­¬¬¬¬¬¬¬¬¬­­¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬««««««««««««««««««««¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬®¬¬«««««««««««««¬«««««««««««««««¬¬­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¿11111111¿11111¿¿1¿¿1¿®®®®®®®®­­­­­­­­­­­­­­­­­­®®®®®®®­®­®®®®¬­¬¬­­­¬¬¬¬­¬­¬¬­­­­¬­¬­¬­¬­¬­­¬­­¬¬­­¬¬­¬­­¬¬¬­¬­¬¬­¬­­¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬««««««««««««««««««¬¬¬¬­¬¬¬¬¬¬­¬««««««««¬«««««««««««««««««««­¬¬¬¬­­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¿1111¿¿1111¿1¿1¿®®®®®®®®®®®®®®®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬­­¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬­­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬­­­¬¬­­­­­­¬¬¬¬­­¬¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬¬¬­¬­­­¬­¬¬¬­­¬¬¬«««««««««««««««««««¬¬¬¬­¬­­¬¬¬¬¬««««««««¬«««««««««««¬¬¬¬¬­­­¬¬¬¬­­­¬¬¬­¬­¬¬¬¬¬­­­¬¬­¬¬¬­­¬¬­¬¬1111111¿1¿¿11¿¿1®®®®®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®¬¬­¬¬¬¬¬­¬­¬¬¬¬¬¬­¬¬¬¬­­­­¬­¬­­¬¬¬¬­¬­¬¬¬¬­¬¬¬­­¬­­­­¬¬¬­­­­­¬¬­­¬­­¬¬¬¬¬¬¬­¬­¬¬¬­¬­¬¬¬¬¬­­­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬««««««««««««¬«¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««¬­¬­­¬¬­¬­¬­¬­¬¬¬¬¬­­¬¬¬¬¬­¬¬­­¬¬­¬¬­¬¬¬¬­¬­¬¬1111111¿1¿1¿¿1¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬­¬¬­¬­¬­¬¬­¬¬¬¬¬¬­¬­­¬¬­­­¬­¬­¬­¬­­¬¬¬­­­­­­­¬¬¬­­¬¬¬¬¬­¬­¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­­¬­¬¬¬¬¬¬¬¬««««««««««««««««¬¬­¬¬­¬¬¬««««««««««««««««««««««««««««««««««««¬­¬¬­­¬¬¬¬­¬­¬¬­¬¬­¬¬¬­­­­­­¬­­¬­¬¬¬¬¬¬­¬­¬¬¬­¬­­¬¬¬­¿11111¿¿¿1¿¿11¿®®®®®®®®®®®­­­®®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­¬­¬¬­¬¬¬¬¬­¬¬­¬¬­­­­­­¬¬­¬­¬¬­¬­¬¬­¬­­­­­­­­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬­­¬¬¬­¬¬¬¬­¬¬­¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««¬¬¬¬¬¬­¬¬«««««««««««««««««««««««««««¬¬¬¬­¬¬¬¬¬­¬¬¬¬­¬­­¬¬­­¬­¬¬¬¬¬¬­­¬¬¬¬­¬­¬¬¬¬­­¬¬¬­¬¬¬¬1111¿¿1¿¿¿¿¿¿11¿¿1¿®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬¬¬¬­¬­¬¬­¬¬¬¬­¬­­­­®­­¬¬­­­­¬¬­­¬­­¬¬¬­¬­­¬¬¬­­¬­¬­¬­¬­¬¬­¬¬¬­¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬¬­­¬¬¬¬¬­­¬¬­«««««««««««¬­¬­¬¬­¬¬¬¬¬­¬«««««««««««««««««««««««««««««««¬¬¬­¬¬­¬­¬¬­¬­­­¬¬­­¬¬¬¬­­­­­­­¬¬¬¬¬¬¬­­¬¬­­¬¬¬¬¬¬­¬¬­¿¿1¿¿1¿1¿¿¿1¿¿¿¿®®®®®®­®®®®®®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬­­­¬¬¬¬­¬¬­¬­¬¬¬¬­¬¬­¬­­­­­­­¬¬¬¬­¬¬­¬¬¬­¬­­­­­­­­¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬­¬­¬¬­­­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬««««««««««««««¬««­¬¬­¬¬¬¬¬¬­¬«««««««««««¬««««««««««««««««««««¬¬­¬¬­¬¬­¬¬­¬¬­¬¬¬¬­¬­¬¬¬¬­¬¬­­­­­­­¬­¬¬¬­­­­¬­¬¬¬¬¬¬¬¬11¿1111¿¿¿¿¿¿11¿®®®®­®­®®®®®®­­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®­®¬¬­­­­­­¬¬­¬­¬¬¬¬¬¬¬¬¬­­¬­®­­¬­¬¬¬¬­¬­¬¬­¬®­­­­­­¬¬¬­­¬¬¬¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬­­¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬«««««««««««««««««¬¬«¬­¬¬­¬¬¬¬¬«««««««««««««««««««««««««««­¬­¬¬¬­¬­¬¬­¬¬­¬¬¬¬­¬¬­­¬­¬¬¬¬­¬¬­¬­­­­¬­­­¬¬­¬­­¬­­¿111¿1¿¿11111¿®®®®®®®­®®®®®­®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­¬­­¬­­¬¬¬­¬¬¬¬­¬¬­¬­¬­­­­¬¬¬¬¬­¬¬¬­¬­¬­­­­­­¬¬¬¬­­­¬¬­¬¬­­­¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬­­­­¬¬­­­¬¬­­¬¬¬¬­¬¬¬­««««««««­­¬¬¬¬¬­­¬¬¬¬¬¬«««««««««««««««««««««««««¬­¬¬­¬¬¬­¬¬¬¬­¬­­¬¬¬¬­¬¬¬­¬¬­¬­¬¬­¬¬­­¬¬­¬¬­­¬¬¬¬¬¬­¬­­¬¬­1111111111¿¿1¿¿®®®®®®­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­­¬­­­®®¬­­¬¬¬­¬¬¬¬¬­­¬­¬­­¬­­¬­¬¬­­¬¬­¬¬®®­­­­¬¬¬­­¬¬¬­¬¬¬¬¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬¬­¬¬¬­¬¬­¬­¬­¬¬¬­­¬¬­¬¬­¬¬¬¬«««««««««««­¬¬¬¬¬¬¬¬«««««««««««««««««««««««««««««««¬¬¬¬¬­¬­¬¬­¬¬­¬­¬¬¬­¬­¬¬¬­­­­¬¬­¬¬­¬¬­¬¬­¬­¬¬­¬­¬­¬¬­¬¬­¬­¬­11111¿1111¿¿¿¿¿¿®®®®®®®®®®­®®­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®­¬­­¬¬¬¬¬¬¬¬­¬¬¬¬­­­­­­¬­¬­¬¬­¬¬­¬¬­¬¬­®­­­­­­­­­¬­¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬­­¬¬¬­¬¬¬¬­¬¬­®­­®¬¬­­¬¬­­­­¬¬¬¬¬¬««««««««««¬«¬¬«¬¬¬¬­¬¬¬¬¬««««««««««««««««««««««««««««««¬¬¬¬¬­­¬­¬¬¬¬¬­¬­¬­¬¬­­¬¬­­¬¬­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬­¬­­¬¬111111¿111¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®­®®®®­®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­¬®¬­¬¬­¬¬­¬¬­¬¬¬¬¬­­­­¬¬­­­­­­­¬¬­¬¬­¬¬¬¬­­­­¬¬¬­¬®­­¬¬¬¬¬¬¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­®®®­¬­¬¬¬¬¬¬¬­­­¬¬««««««««««««««¬¬¬­­¬¬¬¬­¬¬¬¬««««««««««««««««««««««««««««««««««««««««¬«¬¬­¬¬¬¬¬­­­­­­­­¬¬­¬­¬­¬¬¬¬­¬¬¬­­¬¬¬¬­¬¬¬¬¬­¬¬­¿11111¿¿1¿¿111®®®®®®®®­®­®®®­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬®­¬­¬¬¬¬¬¬¬¬¬­¬¬¬­­­­¬¬¬¬­¬¬­¬¬¬¬­­®®®­­­­­­¬¬­­­­­­¬¬¬¬¬­¬¬­¬­¬­¬¬¬­­­¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬®®®®®®®­­­¬¬­¬¬­¬¬­¬¬««««««««««­«¬«¬¬¬¬¬¬¬¬¬««««««««««««««««««««««««««««««¬­¬­¬¬­­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬­­¬­¬­¬­¬¬¬¬¬¬­¬¬¬­¬­¬¬¬11111¿¿¿¿¿¿111¿®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­­®­­¬­­¬¬­¬­¬¬­¬¬¬­­¬­®­­¬¬­¬­¬¬¬¬­¬­­®®®­­¬­¬­¬­¬­¬­­¬­¬­¬­¬¬¬¬¬¬­¬¬­¬¬­¬­­­¬­¬­¬¬­¬¬­¬­¬­¬¬¬¬¬­¬­®®®®®®®®¬¬­¬¬­¬­¬­¬¬¬««««««««¬¬«««¬¬­¬¬¬¬««««««««««««««««««««««««««««««««¬¬¬¬­¬­¬¬­¬¬­¬¬­¬¬¬­¬­­¬¬¬­­¬¬¬¬¬¬¬¬­¬¬­¬­­¬­¬­¬­¬¬­¬¬11111¿1¿¿1111¿¿®®®®®®®®®®®®®®®®®®­®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬¬¬­¬­­¬­¬­¬­­­­®­¬®­¬¬­¬¬­¬­¬¬¬­®­®®­­¬­¬¬¬­¬­­¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬¬­­®®®®¬¬¬­¬¬¬¬¬¬««««««««««­«¬¬¬¬¬¬¬¬­¬««««««««««««««««««««««««««¬¬¬­­­¬¬­¬­¬¬¬­­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬¬­­¬­­¬¬¬­111¿1¿¿1¿11¿¿¿¿¿®®®®®®®®®®®­®®®®­­®­®­­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­¬¬­¬¬­­­­¬­¬®­¬¬¬¬¬¬¬­®®­­­¬­­¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬­¬­¬­¬¬¬¬­­¬­¬¬¬¬¬­­¬¬¬¬¬­¬¬­¬­­­­­¬¬¬¬¬¬«««««««««««««««««««¬¬¬¬¬¬¬¬­«««««««««««««««««««««««««««««««««««««¬­®®¬­­¬¬­¬¬¬¬¬¬¬­¬¬­¬¬­­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬­¬111¿1¿¿¿¿¿¿®®®®®®®®®®­®®®®­®®®­®®®®®®®­®­®®®®®®®®®®®®®®®®®®®®®®¬®­­­­­­­¬¬¬­¬¬¬­­¬¬­­­­¬­­­¬­¬¬­¬¬­®®­­¬­­¬­¬¬¬¬­­¬¬¬¬­¬¬­¬®®¬­¬¬­­¬­¬¬¬¬¬­¬¬¬­¬¬¬­¬¬­¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬¬««««««««««¬««¬¬¬¬¬¬­¬¬¬¬­««««««««««««««««««««««««««««««««««««¬®¬¬¬¬­¬¬­¬­¬¬¬¬¬­­­¬­¬¬­¬­¬¬­¬¬¬­­­¬¬­¬¬­­¬¬¬¬­¬¬­¬¬¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­®®­­­­¬­­­­®­­­­­­­¬¬¬­¬¬¬¬¬¬¬­¬­­­®®®®­­­­¬¬­¬¬¬¬¬­¬¬¬¬­¬­¬­­¬­­¬­¬­­­­¬­¬­¬¬¬­¬««­­¬¬­­¬¬¬¬¬¬­­¬¬««««««««««««««««««««««««««««««¬­¬¬¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬­­­¬­¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬­­¿¿1¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®®­¬­­­¬¬­­®®®­®¬¬¬¬¬¬¬¬­¬­¬¬­¬­¬­­­­®­®®­¬¬­­¬¬­¬¬­¬¬¬­¬­¬­¬¬­¬¬­¬¬­¬­¬­­­®®¬­¬­¬¬­¬¬­¬¬¬¬¬«­¬­¬¬¬¬¬­¬¬­¬¬¬­¬¬¬«««««««««««««««««««««¬­®¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­­¬­­­¬¬¬¬¬¬­¬­­¬¬­­¬¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­¬¬¬­­­¬­­­®®­¬¬®¬­­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬­¬­®­®®®®®­¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬­¬¬­­­­¬­­­­­­­¬¬­­­­¬¬¬¬¬¬¬¬­¬¬­¬­¬­¬¬­­¬¬­¬¬¬¬««««««««««««««««««¬«­­­­­¬¬¬¬¬¬­¬¬¬¬­¬¬¬­­¬­¬¬¬¬¬­¬­­¬¬¬­¬¬¬¬­­­­¬¬¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­¬­®®­¬­­­¬¬­¬­¬¬¬­¬¬¬¬­¬¬¬¬­­­­®®­®¬¬¬¬­¬¬¬¬­­¬¬­¬­¬¬­¬¬­¬¬­­­­­­­­¬¬¬¬¬¬­¬­­­¬««¬¬¬­¬¬­¬¬¬­¬­­¬¬¬¬««¬«««««¬««««««««««¬¬¬­¬¬­¬¬¬¬¬¬­¬­¬¬­¬¬¬­¬­¬¬¬¬¬­¬¬­¬¬­¬­­¬­¬¬­­­­¬¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­­®®®®­¬­­­¬­¬­¬­¬¬¬¬¬¬­­­­­­®®­­®®¬¬­­¬­¬¬­¬­­­¬¬¬­¬¬¬¬¬¬¬­­­­¬­¬¬­­­­¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­¬­¬¬­¬«««««««««««««««««««¬­­¬¬­¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬­¬­­­­¬­¬¬­¬¬¬­¿¿¿®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­¬®¬¬¬­¬¬­¬­¬­¬¬¬¬­­¬­­­®­®­­¬­¬¬­¬¬­¬¬­¬¬¬¬®­­¬­¬­¬¬­­­­­¬¬­­­­¬¬¬­¬¬¬¬¬¬¬¬«¬¬¬¬­¬¬¬¬­¬­¬­­¬«««««««««««««««««­««­¬­­¬­­­¬­¬¬­­¬¬¬¬¬¬¬­¬­­¬­¬¬­¬­¬­¬¬­¬¬­­¬¬¬¬¬­¿¿®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­®®®¬­¬¬¬­¬¬¬¬¬­­¬¬¬­¬¬­­®­­­­®®®®®®®®¬¬¬¬­¬¬­¬¬®­­¬¬¬­­­­­¬­¬¬­¬­¬¬¬¬¬¬¬­¬­¬¬«¬¬¬¬¬¬¬¬¬¬¬¬­¬¬««««««««««««««««««««««¬­¬¬¬¬¬­¬­¬¬­¬¬­¬¬­¬¬¬¬¬¬¬¬­¬¬­¬­¬¬¬¬­¬¬­­­­­­¬¬¬¿®®®®®®®®¿®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®­®®®­­­­­­­­®®­­­­­¬¬¬¬¬­¬­¬¬­®­­­­­®®®®®®®®®®®¬¬¬¬­¬­¬¬­¬­¬¬­­¬­¬¬­­­­¬­¬¬­­­¬­¬¬¬­¬¬­¬¬­¬¬¬¬¬«¬¬¬¬¬¬¬¬­¬¬­¬­¬¬¬­­«««««««««««««««««««¬­¬¬­­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬­¬­­¬¬¬¬¬­¬¬¬­­¬¬­¬­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®­­¬­­­®®­®­­­­­­­¬¬¬­­­­­­­®®®®®®®­®®®­¬¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­¬­¬¬­¬¬¬¬­­­¬­¬¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­­­­­®®®¬­¬­­¬¬¬«««««««««««««««««««««¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­¬¬¬¬¬­¬­­­¬­¬­¬¬®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®®®­­­­­­¬­­­­®®­¬­¬¬¬¬¬¬­¬¬­¬­­®®®®®®®®®®®®®®­­­¬­¬¬­¬¬¬¬¬¬­­¬­¬¬¬¬¬­¬­­­­¬¬¬¬­¬­¬¬¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬­¬¬¬­¬­¬­­¬¬­¬­­­¬««««««««««««««««««««««¬¬¬­¬­­­­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬­­¬¬­¬¬¬¬¬¬¬­­­­¬¬­®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­¬­­­®­­­¬­¬¬¬­­­­­­­®®®®®®­®­®¬­¬­¬¬¬­­­¬¬¬¬¬¬­­­­­­­­­­¬¬¬¬¬¬­­­¬­¬¬¬¬¬¬¬¬­¬­¬¬­¬­¬­¬­¬¬®­¬­¬­­­««««««¬«««««««««««««¬®­«¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­­­­­­­­­­­­¬®¬¬­¬¬¬­­­­­®®®®®®®®®®®®¬­¬¬­¬¬­®­¬­¬­­¬­¬¬¬­¬­­­®®®®­­¬¬­­¬¬­¬¬¬­¬¬¬¬¬¬¬­­«¬­­¬­¬­¬­­¬¬¬­­¬«««««««««««««¬¬«­¬­­­¬¬­¬¬¬­­¬¬­¬­¬¬­¬¬¬­­­­¬­­¬­­¬¬¬­­­¬¬­¬¬®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­­­­®®®®­­¬¬¬®®­­¬¬¬¬¬¬­­­­®®®®®®®®®®®®®¬¬¬­¬­®¬­¬¬®®¬­­¬­­­¬­­­®¬­­¬­­­­¬¬­¬¬¬¬¬¬¬¬¬«¬¬¬­­­¬¬­¬¬¬¬¬­­¬«««««««««««««««««¬¬¬¬«¬¬­­­­¬¬¬¬­¬¬¬¬­¬¬­­­¬¬­¬¬­¬­¬¬­¬¬¬­­¬¬¬­­­­­¬¬­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬­®­¬¬¬­­­¬¬¬¬¬¬¬­­­­­®®®®®®®®®®®­®¬­¬¬­­¬¬­¬¬­­¬¬¬¬­¬®­­­®®¬­¬¬­­¬¬­­­®¬¬¬¬¬¬¬¬¬¬¬¬«¬¬¬¬­¬¬­¬¬­­¬­­¬¬­­¬¬««««««««««««¬¬««¬­¬­­­­­­¬­¬­¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬­­¬¬¬­­®­­¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­®®­­­­­¬¬¬¬­¬¬¬¬¬¬­­®®®®®®­®®®­¬¬­¬¬®­¬¬­®­¬­¬­­¬­¬­®­­­­®®­¬­¬¬¬­¬®­­¬¬­¬¬¬¬¬¬¬«¬¬¬­¬­­­¬¬¬­¬¬¬­¬­¬¬¬««««¬««««««««««¬¬¬¬¬­­­¬¬­¬¬­¬­¬¬¬¬­¬­¬­¬¬¬­¬¬­¬¬­¬¬­¬¬­¬­­­­¬¬®­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬­­­­¬­­­­®­­­­­­­­¬¬­­­¬¬¬¬­¬¬­­®®®®­¬¬¬­­¬¬¬­­¬¬¬­¬¬¬¬¬­¬¬­­­¬®®­¬¬­¬¬¬­¬¬­¬­­¬¬¬¬¬¬¬«­­­­¬¬¬­­­­¬¬­¬¬¬¬¬««««««««¬««««««««««««¬¬«¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬­¬¬­¬¬­¬­­¬¬­¬­¬¬­¬¬­¬¬­¬¬¬­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­¬­­­­­­­­­¬¬­¬­¬¬­­­­­¬­¬¬¬­¬­­¬¬¬­¬¬¬¬¬¬¬­¬¬¬­­­®¬­¬­¬¬¬¬­­¬­­¬­¬¬¬­¬¬¬¬¬¬­­¬­­¬­¬­­¬®®®®­­­­®®®¬­¬¬­­­¬­¬­¬­¬¬¬¬­¬¬¬¬¬¬¬«¬­¬¬¬¬¬­¬­¬­¬¬¬¬­¬­¬¬«««««««¬­¬¬¬«««¬¬¬¬­¬­¬¬¬¬­¬¬¬­¬¬¬¬¬­¬¬¬¬­­­¬¬¬¬¬¬­¬­­¬­®¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­¬­¬­­¬­­¬¬¬¬­¬¬­­¬¬­¬¬¬­¬¬­¬­­­­¬¬­¬­¬¬­¬¬¬­¬­¬¬¬­¬­­¬¬¬¬¬­­­¬­¬¬­®¬¬­­¬¬¬¬­­­­¬¬­¬¬®®®®®®®®®­¬­­­¬­­­¬¬­¬¬¬¬­¬¬¬¬­¬­­¬¬¬­­¬­¬¬«««««««««««««««««¬«¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬­¬­¬¬¬¬­¬­®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­¬­­­­­¬­¬¬­¬­¬­­¬¬­­­¬­­­¬¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬­­­­­­¬¬¬­¬­¬¬­¬¬­­­¬¬¬¬­¬­¬®®®®®®®®­®®®¬¬¬¬­¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­¬¬®­­­¬­¬¬­¬«««««««««««««««¬¬¬¬¬­­­¬¬¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­­¬¬­¬®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­­¬­¬­¬¬­¬­¬­¬­­­­­­­­­¬¬­­¬¬­¬­¬¬¬¬¬¬­­¬­­¬­¬¬­¬¬­­­¬­®­¬¬¬¬­­­¬­¬­¬­¬¬¬¬­¬¬­¬¬®®®®®­®®®­­­¬¬¬¬­¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬­¬®®®¬¬­­¬¬«««««««¬«««««««««­¬¬­­­¬¬¬¬­­¬¬¬­¬¬¬­¬¬¬¬­¬¬­®¬¬®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­®­­­­­­­¬­­­­¬­­­¬­¬­­­­¬­­­¬­¬¬¬­­­¬­¬¬¬­¬¬¬¬­¬¬¬¬­¬­¬­¬¬¬­­¬¬¬¬¬­¬­­­®®®®®®®®®¬­­­¬¬­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬­­­­¬¬­¬¬««««««««¬«««««««««««««««¬¬­­¬¬­­¬¬¬¬¬¬­¬¬¬¬­­¬¬¬¬­­­­®¬­­­®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­¬¬¬¬­­­­­­­­¬¬­¬­¬¬­¬­¬­­­­¬¬­­¬¬¬¬¬¬¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬­¬­­¬¬­¬­¬­¬­¬¬­¬¬¬¬­¬¬­­­­®®®®®®­­¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬¬®­¬®­­­¬¬¬¬««««««««««¬«««««««««¬««««¬¬¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­­­¬¬¬­­®®¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­­¬¬¬¬¬¬­¬¬¬­­­­­­¬­¬­¬¬¬¬­¬¬¬¬¬­¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬¬¬­­¬¬­¬¬­¬¬¬¬­­­®­­­®®®®¬­¬®¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬­­­¬¬®­¬¬¬««««««««¬««««««««««««««¬­¬­­¬­¬¬­­¬¬¬¬¬¬¬­¬¬¬­­­¬­­®­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­­­¬¬­­­¬¬­­¬¬­­­­¬­¬¬­­­¬¬­¬¬­¬­¬­¬¬­¬­­¬­¬¬­­¬­¬¬­¬­¬¬­¬¬­­¬¬¬¬­­¬¬­¬­¬­¬¬­­®­®®®®®®®­­­¬¬­¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­­¬­­¬¬¬««««««««««««««««««««««««««««¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­­­­­­¬­­­­­­­¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­­­­­­­­­­¬¬­¬¬¬¬¬­­¬¬­­­­¬¬¬­­¬¬­¬¬­¬¬¬­­¬­¬¬¬¬­­­¬¬­¬¬­¬¬¬¬­­¬¬¬­¬­¬¬­­¬¬­¬¬¬¬­¬¬¬¬­­®®®®®®®¬­¬¬­­­¬¬¬­¬¬¬­¬­¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬««««««««««««««¬¬¬¬­®­¬¬­¬­¬¬¬¬­¬¬­­¬­¬¬­­­­­­­¬­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬­­­­­­¬­¬¬¬­¬­¬­­¬¬­­­­¬­¬­®­¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬¬­¬­¬¬­¬­¬¬­¬¬­¬¬­¬¬­¬­­­®®®®®®®¬¬¬­¬­­¬­¬¬¬¬­¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬­­¬¬­¬¬­¬¬¬¬«««««««««««««««««««¬¬¬¬¬®­¬­¬­¬¬¬¬­­¬¬¬¬¬­­¬­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®1¿¿¿1¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­­®®®­­­®­­­­¬¬¬¬¬­¬­­­­¬­­­¬¬­­¬­¬­­­­¬­¬¬¬¬¬­­¬¬­¬­¬¬­¬¬¬¬­­¬¬¬­¬¬¬­¬­­¬­¬­¬¬­¬¬­¬¬¬¬­®®®®®®¬¬­¬­­¬­­­­¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬­­­¬¬­¬¬­­¬­«««««¬««««««««««««««««««««««««««¬¬¬­­¬­¬¬¬¬¬¬¬¬¬¬­­¬¬¬­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿1¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­­­®­¬¬­¬­¬­­­¬­­­¬­¬¬­¬­¬¬¬­¬¬¬¬­¬¬¬­­¬¬¬¬¬­¬­¬¬­¬¬¬¬¬­­¬¬­¬¬¬¬­¬­¬¬­­­¬­®®®®­­¬­®®®®¬­¬¬­­¬¬¬­¬¬¬¬¬­¬¬­¬­¬­¬¬¬¬­¬¬­¬­­­­­¬¬¬¬«««««««««««««««««««««««««¬¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­®­­­­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­¬­­­­¬¬­­­­¬¬¬¬¬¬¬¬­­­­­¬­­­­­­¬¬­¬­¬¬¬¬¬­­¬¬®­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬­¬­¬¬¬¬­¬¬­¬­­­®®®®­­¬­­®®®¬­¬¬¬­­­¬­¬¬­¬¬­¬¬¬­­¬¬­¬¬¬­¬¬­¬¬­­¬«««««¬¬¬««««««««««««««««««¬¬­¬­­­­­¬­¬¬¬¬¬¬¬¬¬¬¬­¬­­­¬­­¬­¬­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­®­­­¬­­­¬¬¬¬­­¬¬­¬¬­­­­¬¬­­­¬­¬¬¬­¬¬¬¬¬¬­¬­¬­¬­­¬¬­¬¬­¬¬¬¬­¬¬¬­¬­¬¬¬¬­¬¬­¬¬­¬­¬­®®¬¬­­®®­­­­¬¬¬­­¬­¬¬¬­¬­¬¬­­¬­¬­¬­¬­¬¬¬¬¬­¬­¬¬­¬¬¬¬««««««¬«««¬««««««««««««««««¬¬¬­­¬¬¬¬¬¬¬­¬¬¬¬¬­­­­­­¬­­­­¬¬­®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®¿1¿¿¿¿¿¿¿1®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®¬¬­­®­­­­¬­­­­¬¬­¬¬­­¬¬­­­¬­­­­¬­­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­­­­­¬¬­¬¬¬­¬­¬­¬­¬¬¬­¬­¬¬¬¬­¬­¬¬­¬­¬­®®®®®®­­­¬¬­­®®­­­¬­¬­¬­¬¬¬¬¬­¬¬­¬¬¬¬¬­¬­­­¬¬¬­¬­¬¬¬««¬«««««««««««««««««««««¬¬­­­­­¬¬¬¬¬­­¬¬¬­­¬¬­¬¬­­­­­­¬¬­­­­¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­­­­­­­­­­¬­­¬¬¬¬¬¬­­­­¬¬­¬¬¬¬¬¬­¬¬­¬¬¬­­¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬¬¬¬¬¬­¬¬¬­®¬­­¬¬­¬¬­¬¬­¬¬­¬®®®®®­¬¬¬¬­®¬¬¬­¬¬¬­­¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬­¬­¬­¬«««««««««««««««««««««¬¬¬­­¬¬¬­¬¬¬¬¬­¬¬¬¬¬­­¬¬­­­­­­­¬­¬­¬¬­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬­¬¬¬¬¬¬­­­¬­¬®®®­¬­¬¬¬¬¬¬¬¬­­¬­¬¬¬¬¬¬­¬­­¬­¬¬­¬¬­¬¬­¬¬­¬¬¬­¬¬¬®®®®­¬®¬¬­¬­¬¬®¬­­­­¬¬¬­¬¬¬¬¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬««««««««««««««««««¬¬­­¬­¬¬¬¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬­­¬¬­­­­­­­­­­­­­¬¬­­®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®­­­­­­­­­­¬¬­¬¬¬­¬¬­¬­­­¬­­¬­­­¬¬¬¬¬¬­¬­¬­­¬¬¬­­¬¬¬­­¬¬¬¬¬¬­¬¬­¬¬­­­¬¬¬­­®¬­­­¬¬¬­­­¬­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««¬¬¬¬¬­­¬¬¬­¬¬­¬­¬­¬¬¬¬­¬­¬­¬­­­¬­­­­¬­¬¬­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­¬­¬­­¬­¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬­­¬¬¬¬¬¬­­­¬­­­­¬¬¬¬­­¬­¬¬­¬¬­¬¬­¬­­­­­­¬­®­¬­¬¬­¬­¬­­­­¬®­­¬¬­­­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬®¬¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬«««««««««««««««¬¬¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬­¬¬¬­­¬¬¬­­­­­­­­¬¬­¬­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬¬­¬¬­¬­¬¬­­¬­­¬­¬¬¬¬¬¬¬­¬­­¬¬¬­¬¬­­¬­­¬­­­¬­¬¬­¬¬­¬¬¬¬¬­­¬­­­¬­®­­¬­¬¬¬­­­­­¬®®­­¬­¬¬­¬¬­­­¬­¬­¬¬­¬­¬¬¬¬¬¬¬¬­¬¬­¬¬¬­­¬­­¬¬­¬¬­­¬¬­­¬¬¬¬¬¬¬««««««««««««««««««¬¬¬­­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­­­¬¬¬­­­­­­­­¬­¬­­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­¬­­­¬­¬­­¬­¬¬­­¬¬­¬¬¬¬¬¬¬­¬¬­­¬¬¬¬¬¬­­¬­¬­­¬­­¬¬­¬¬­¬¬¬¬­¬¬­­­¬¬­¬¬®­®®­­­¬¬­¬¬­¬­®­¬­¬¬¬¬­¬¬¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­­­¬¬¬¬«««««««««««««««««««¬¬¬¬¬­­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­­­­­­­­­­­­­­®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­­­­­­¬­­­¬¬­¬¬¬­­¬¬­­¬¬¬¬¬¬¬­¬­¬¬­¬¬¬¬¬­¬¬¬­¬­¬­¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬¬­®­¬­­­¬­¬¬­¬¬¬¬­­¬¬¬­­­¬¬¬­¬¬¬­¬¬­­¬¬­¬¬­¬¬¬¬­¬¬¬­­¬¬¬¬¬­¬¬­¬¬­¬««««««««««««««««««««¬¬­­¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬­­­¬¬­­­­­®­­®®­­­­¬­­¬¬¬¬­­®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®­­­­­­¬­­¬­¬¬­­¬¬­­¬­¬¬¬¬¬­­¬¬­¬¬­¬¬¬¬­¬¬­¬¬­¬­¬¬­­¬­¬¬­¬­¬­¬¬­¬­¬¬­­­­¬­­¬­¬­­­¬­¬­¬¬­­­®­­¬¬­­¬­¬­­­¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬¬­­¬¬««««««««««««««««««¬­¬¬¬­¬­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­¬­­­¬­­­­®­­­¬¬¬­¬­­®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬­¬­¬­¬­¬­¬­¬¬­­­¬­¬¬¬¬¬­¬­­¬¬¬­¬­¬­¬­­­¬¬­¬­¬¬­­¬­¬­¬¬­¬­¬­­­­­¬¬¬¬¬­­­¬­¬­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬­¬­¬¬¬«««««««««««««««««««««««««¬¬­­¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬­¬­­­­­¬­¬¬­­­­­¬®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­­­­­­­­¬¬­¬­¬­¬¬¬¬¬­¬¬­­­¬¬¬¬¬¬¬­­¬¬¬¬¬¬­¬­­­¬¬¬­¬­­­­¬¬­¬¬­¬¬­¬­¬¬­­­­­­¬­¬¬¬­®­­¬¬­¬­¬¬­­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬­¬¬­¬¬¬¬¬¬¬««««««««««««««««¬¬­­¬­¬¬¬­¬­­­¬¬¬¬¬­¬­­­­­­­­­­­­­­­­­­®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­¬­¬¬­­­¬¬¬¬­¬­¬¬¬¬¬¬­®­¬­¬¬¬¬¬¬¬¬¬­­¬­­­¬¬­­¬­¬­¬­­­­­­¬­¬¬¬­­¬¬¬­­¬­­­­¬­¬¬­­­­­­¬¬­¬¬¬¬¬¬¬¬¬­­¬¬­¬¬¬­­­­­¬¬­¬­¬¬¬¬¬«««««««««««««««««««««¬¬­¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬­­¬¬­¬­­­­­­­¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­­¬¬­¬¬­¬¬­­¬­¬¬­¬¬¬¬­­¬¬¬¬¬¬¬­­¬¬­¬­¬­­¬­¬¬¬¬¬­­¬¬­­­¬®­­­­¬¬­¬­­­¬¬¬¬¬¬­¬¬­¬¬¬­¬¬­­­¬¬¬¬­¬¬¬¬¬¬­¬­¬¬¬¬­¬¬¬¬­¬¬¬¬«¬¬«««««««««««««««««¬¬­­­¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬¬­­­­­­­­¬¬¬¬¬­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬¬­¬¬­¬¬­¬¬­­­¬¬¬­­¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­­¬¬¬­­¬¬­¬­¬¬¬­¬®­¬¬­­­­­­­­¬¬­®­¬­­­­¬­¬¬­­¬­¬­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬¬¬¬­¬¬­¬­¬¬­¬¬¬¬¬¬«««««««««««««««««¬¬¬¬­¬­¬¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­¬­®­­®®­­­­­­®®®®®®®®®®®®®®­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­¬­¬­­¬¬¬¬­­­¬¬­¬­­­­¬¬¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­¬­¬­¬¬­¬­¬­¬¬­®­¬­­­­¬­­­¬¬­­­­­­­¬­­¬¬­­¬­¬­¬¬­­­¬­¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬««««««««««««««««««««¬¬­¬­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬¬¬¬­­­®¬¬¬¬¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬­¬¬­¬¬¬¬­¬¬­¬­¬¬­­­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬­­­­¬¬­¬¬¬­¬­­­¬­­­­­¬¬­¬¬¬­¬¬¬¬­¬­­¬¬¬­­¬­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬­­¬¬¬¬¬¬­­­¬¬¬¬¬¬¬««««««««««««««««««««¬¬­­¬­¬¬¬­¬¬­¬¬¬¬¬¬¬­¬¬¬­­¬­­¬­­­­®®®­­­¬®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®­­¬­¬­¬­¬¬­¬¬¬¬­¬¬­¬­¬¬­­­¬¬¬¬­¬­­­¬¬¬­¬¬¬­­¬­¬¬¬¬­¬¬­­¬­¬¬­®­­­­­­­­­¬¬­¬¬­¬¬­¬­­­­­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­­¬­¬¬¬¬¬¬¬¬¬¬¬¬«««««««««««««««««««¬­¬¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬­­¬­­­­­­®®­­®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­¬­¬¬¬­¬¬­¬­¬­¬­¬­¬­­­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬¬­¬­¬­­­­­­¬¬­¬¬¬­­­­­¬¬­­­­¬­¬¬­­­­¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬¬¬­¬¬­¬¬¬¬­­¬¬­¬¬¬¬¬¬¬­¬­¬­­¬¬¬¬¬¬¬«««««««««««««««««««««¬¬¬­¬¬¬¬¬¬¬­­­¬¬­¬­­­¬¬¬­­­­­­­­­®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­­¬­¬¬­¬¬­¬¬¬¬­¬­­­¬­­¬¬¬¬­­¬¬­¬¬¬¬¬­­¬­¬¬­­¬­¬¬­¬¬¬­­¬­­®­­­­­­­­­­®­­­­®­¬­­¬¬­­­­¬­­­­¬¬¬¬¬­­¬­¬¬­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬««««««««««««««««¬¬¬¬­¬¬­¬­­­­¬¬¬¬­¬­­¬®­®®­®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­¬¬­¬¬­¬­¬¬­¬¬­¬­­­­¬­¬­­¬­¬¬­¬¬¬¬¬­¬­­­¬¬¬­¬¬­¬­­­­­­­­­­­­­­­¬­­¬­­­¬­­¬­­­¬¬­­­­¬¬­¬¬¬¬¬¬¬­¬­¬¬¬­¬¬­¬­­¬¬¬¬¬¬¬¬­¬­­¬­¬¬­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬­¬««««««««««««««««¬¬­­­¬¬­­­­­­­­­¬­­­­­¬­¬­­®®®®®®®®®®®®®­­­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®­­¬­­­­¬¬¬¬­¬¬­¬¬­­¬­­­¬­¬¬¬¬­­¬­¬¬¬¬­¬¬¬¬¬­­­­­¬­­¬­­­®­®­­­®­­­­­­­­­­­­­®®¬­¬­¬¬­­®­­­¬­¬¬¬­­­¬­¬¬¬­­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬¬­¬¬¬­­¬¬¬¬­¬¬¬¬¬¬«««««««««««««««««¬¬¬­¬­¬¬­¬­­­­¬¬­¬­¬­¬¬­­­®®­®®®®®®®®®®®®­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­¬¬­¬¬­¬¬­¬­¬¬¬¬¬­¬­¬­¬­¬¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬¬­­­®®­­®®­­­­­­­­­¬­­®­¬­¬­¬¬­­¬¬­¬­­¬­¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬­­¬¬¬­¬¬­¬­­­¬¬¬­¬¬­¬¬­­¬¬¬¬­­­¬¬¬¬««««««««««««««¬¬­­¬­¬¬­­­­­­­­¬¬­­­­¬­®®®®®®®®®®®®®­®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­¬¬­¬­¬¬­¬¬¬­¬­¬¬¬­¬­­¬¬¬¬¬¬­­¬¬¬¬¬¬­¬¬¬­­¬­¬­¬­­­®­­®®®®­­­­­­­­­­­­¬­­®®¬­¬¬­¬®®®®®­­­­¬¬­¬¬¬¬¬¬­­¬¬­¬­­¬¬­­¬­¬¬¬­¬¬¬¬¬¬­­¬¬¬­¬¬¬­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬«««««««««««««««¬­­­¬¬­¬­­­­¬­­­¬­­­­­­­­­­­­­®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®­­¬­¬¬­¬¬­¬­¬¬¬­¬¬­¬­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­­¬¬­­­­®®®­­­­­­¬­­®¬­¬¬­®­¬­¬­¬¬­­¬­¬¬¬¬¬­­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­­¬­¬­­¬­­­¬¬¬¬­­­­¬¬¬­­¬¬¬­¬««««««««««««««««¬­¬­¬¬­¬¬¬¬­­­­­­­­­­­®¬­­­­®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®­­¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬¬­­­¬­­­¬­­­­¬¬¬¬¬¬¬¬¬¬­¬­¬­­­¬¬¬­®­­­­­­­­­­­­­­­®®®®­¬¬¬¬­¬¬­¬¬¬¬­¬¬­­¬¬­­¬¬¬¬¬­¬­­¬¬¬­­¬­­¬¬¬¬­¬¬­¬¬­¬­¬­­¬¬¬¬¬¬¬­¬¬¬«««««««««««¬­­¬¬¬¬­¬­­­¬¬¬¬¬­­­­­­­®®®­­­®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®¬­­¬¬¬­­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬¬¬­¬­­¬¬¬¬¬¬­¬­­­¬­¬¬¬­­­®­­­­­­®­­­­­­¬¬­¬¬­¬­­­®­¬­­¬­¬¬¬­¬¬­­­­¬¬­¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬­¬­¬­­­¬¬¬¬­¬¬¬¬¬««««««««««««¬­¬¬¬®¬¬¬¬­­­­­¬¬¬¬­­¬­­®®®­­®®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®¬­¬¬­¬¬­¬¬¬¬¬­¬¬­¬¬­¬­¬­¬­¬¬­­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬­­­¬­­­­­­­­®­­­¬­­­­­¬¬¬­®®­­­¬¬­¬¬¬¬¬­¬­¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬¬¬­¬¬­¬¬­¬­¬­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬«««««««««««««¬¬­¬­­­¬­¬¬­­­­­¬­­­­­®®®®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­­¬¬­¬¬­¬¬­¬¬­¬¬­­¬¬­¬¬¬­­¬¬­­¬­¬¬¬­¬­­¬­­¬¬¬¬¬¬­­­­­­®®­¬­­®­­¬­­¬­­­­­®®®­¬¬­¬¬¬¬­¬­¬­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬¬­¬­¬­­¬¬­¬¬¬­¬¬­¬¬¬¬¬¬¬¬­««««««««««««««¬¬¬¬­¬¬®¬¬¬¬­­¬­­®­­­­­­®®®®®®®®®®®®®®®®®®­®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­¬¬­­¬¬­­¬¬­¬¬¬­­­¬­¬­­¬¬­¬¬¬­­¬¬­­­­¬­­­­­­­­®­¬­®¬¬¬­¬­¬­­­®®®­­­¬¬­¬­¬¬­¬¬¬¬¬¬­¬­­¬¬¬­¬¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬­­¬¬­¬¬¬­¬­¬­¬­¬¬¬¬­¬­­¬¬­­¬¬¬¬¬¬«««««««««««««¬¬­¬¬­¬­­¬¬­¬¬­¬¬­¬¬­®­®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­¬¬­­¬¬­¬­¬¬­¬¬¬­¬¬­­¬­¬­­­¬¬¬¬­­¬¬­­¬¬­­¬­¬­®­¬­®­¬¬¬¬­¬¬¬¬­­­­®®­­­­­¬¬­­¬­­¬­¬¬­¬¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬­­¬¬¬¬¬­¬¬­¬­­¬¬¬¬¬­¬¬­¬¬¬¬¬¬««««««««««¬¬­¬­­¬®¬¬­¬­­­­­¬¬¬­­­­­­®®®®®®®®®®®®®­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬¬¬­¬¬­¬¬­­¬­¬­­­­­¬­­¬¬­¬­¬¬¬­¬­¬¬­¬¬¬¬¬­¬­¬¬¬¬­­®®®®®®®®®­®®¬­¬­­­¬­­¬­¬¬­­­­®®®®­­¬¬­¬¬­­¬¬¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬­¬­¬¬­¬¬¬­¬¬¬¬¬­­­¬¬¬­­¬¬¬¬¬­¬¬¬«¬«««««««««««­­¬­¬­¬¬­­­¬¬­¬¬¬­­¬¬­®®®­®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬­­­¬­¬¬¬¬¬¬­¬­¬­¬­¬­­¬¬­­¬­­¬¬¬¬­¬¬¬¬¬­­­­­­¬­­­­®®®®®®®®®®®®­­­¬®¬®®®®®­¬­­­¬­­­­­®­­­­¬¬­­¬¬­¬¬¬­¬­­¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬­¬¬­¬¬¬¬­¬­¬­¬¬­¬­¬¬­¬­­¬¬¬­­­¬¬¬¬¬¬¬¬¬«¬«««««««««««­¬¬¬­­­¬­¬­­¬¬¬­¬­­­¬­­­­¬­®®®®®®®®®®®®®®®®­®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬¬¬­¬¬¬­¬­­¬¬­­¬­¬¬­¬­¬­¬­¬¬¬¬¬­­¬­¬¬­¬¬­¬­¬¬­­­®®®®®®®­®­¬®®­¬­­­­­­®®­­¬­¬¬­­­­­¬¬­­¬­­¬¬¬¬¬¬¬­¬¬¬¬¬­¬¬­¬­¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬­¬¬¬««««««««««¬­¬¬­¬¬­¬­­­­¬­­¬¬­­­­®­®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­¬¬­¬­¬¬­¬­¬­¬¬­¬­¬¬¬¬¬­­­¬¬­¬¬¬¬¬¬­¬­¬­¬¬¬¬­¬¬­­­¬¬­­­®®®®®®®®®®®®®­­®­­­¬­­¬¬¬¬¬¬­¬­¬¬­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬¬¬¬¬¬­¬¬¬­¬¬­¬¬¬­­­¬­¬¬¬¬¬¬­­¬¬¬¬¬¬¬­¬«««««­­­­¬¬¬­­®®®®­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬¬¬­¬¬¬­¬¬¬­¬­­¬¬­­­¬¬¬­¬¬­­­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬­­¬­¬­¬­®®®®®®®®®®®®®®®®­®®­­­­­­­­¬­¬­¬¬­­­­­¬¬­­­­¬­­­¬¬¬¬­¬¬¬®¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬­¬¬­­­­¬­­­¬¬­¬¬¬­¬¬¬¬­­¬­¬­­­­¬¬¬««¬««¬­¬¬­¬¬­¬®¬­­®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­¬¬¬­¬¬­­¬­­¬­­­¬­­­­¬­­­¬­­¬­¬­¬¬¬­¬¬¬¬¬­¬¬­¬­­­­¬®®®®®®®®®®®®®®­­­®­­®®¬¬­­­­­­­¬­­¬¬¬¬¬¬¬¬­¬­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬¬¬¬­­¬­­­­­­­­¬­¬­¬¬­­¬­¬¬¬¬¬¬­¬¬¬¬¬«¬««««««¬¬¬­¬­¬¬®¬¬®®®®®®®®®­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­¬¬­­¬¬¬­¬­­¬¬¬¬­­¬¬¬­­­­­¬­¬¬­¬¬­­¬®®¬­¬¬­¬­¬¬­¬¬¬¬­¬¬®®®®®®®®®®®®®®­®®®®®®®­¬­­­­®­­¬­­­­­­¬¬¬­­¬¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬­¬­­­­­­­¬­­­¬­¬­¬­¬­¬¬¬¬¬­¬­¬¬¬¬««««««¬¬­¬¬¬¬®­®®®®®®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­¬­¬¬¬¬­¬¬­¬­­¬¬­­¬­­­­­¬¬­¬­¬­­¬¬¬¬®®­¬¬­¬­¬¬¬­¬­¬¬­®®®®®®®®®®®®®®®®®®­­­­­­­­­®­­¬­­¬­­­­­¬¬­­­¬¬­¬­¬­¬­¬­­¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬­¬­­­­­­­­­­¬­¬¬­¬¬­­¬¬¬¬­¬¬­¬¬¬¬¬¬««¬­¬¬¬¬­­®­¬¬­®®®®®­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­­¬¬­¬¬­¬¬¬¬­­­¬­­­¬­­­­¬­¬­­®®®¬¬¬¬­¬¬¬­¬¬¬­¬®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­­¬­­¬¬¬¬¬­­­¬¬¬­­¬¬¬­­¬¬¬¬­¬¬¬­¬¬¬¬¬¬¬¬­¬­­¬­¬­¬¬­­­­­­­­¬¬­¬­¬¬­¬¬­¬¬¬¬­¬­¬­¬¬¬«««¬¬¬¬¬¬­­­­­­­®®­¬­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬­­¬¬¬¬­¬­¬­¬¬­¬­¬¬¬­¬­¬¬­¬¬¬­¬¬­¬¬¬­¬¬¬¬­­¬¬­®®®®®®®®®®®®®®®®­®­¬¬­¬¬­­­¬¬¬¬­­­­­¬¬­­­¬­­¬¬­­¬¬¬¬­¬­¬¬¬¬¬¬­­­­­¬¬­¬¬­­­¬­­­­­¬­¬¬­¬¬¬­­¬¬¬¬¬¬­­¬¬¬¬¬¬««««¬¬¬­¬­­­­­®¬¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­¬¬­­­­­¬¬­¬¬¬¬­¬­­¬¬¬­­­¬¬­¬­­¬¬¬­¬­¬­¬­¬¬­¬¬­¬¬­¬¬­­­¬¬¬­¬¬­¬­®®®®®®®®®®®®®®®¬­­­­­­­­­­¬¬¬¬¬¬¬¬­¬¬­¬¬¬¬­­­¬¬­¬­¬¬¬­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­¬¬­¬­­­­­­­­¬­¬¬¬¬¬¬­¬¬­¬¬­¬¬­¬¬¬­¬¬«««««¬¬­¬­¬­®¬­­¬­­­­­¬®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬¬¬¬­­¬¬¬¬­¬­¬­­­­¬¬­¬¬¬­­¬­¬­¬¬­­¬¬­¬¬­¬¬¬­¬­¬¬¬¬­­¬¬­¬¬¬­¬®®®®®®®®®­®®¬¬­¬­­¬¬¬¬¬¬­¬­¬¬­­­­¬¬­¬¬­¬¬­¬­¬­­¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬¬­¬¬­¬¬­­¬­­­­­­¬­¬¬¬­¬¬­¬­­­¬¬¬¬¬­¬­¬¬«««¬¬¬¬¬¬¬­¬®¬­­­­­­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­­­­­¬­¬¬­¬¬­¬¬­¬¬¬¬­­­­¬­¬¬­­­¬¬­­¬¬­¬¬¬¬­¬¬­¬­¬¬¬­­¬¬®®®®®®®®®®®­®­­¬¬­­­­¬¬­­­¬¬¬¬¬­­¬¬¬­¬­­¬¬­¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬­¬¬­­¬­­¬­­­­¬­¬¬¬­¬­¬­¬­¬¬¬¬¬­¬¬¬¬«««««««¬¬¬¬­¬­­­­­­­­¬­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬­­¬¬­¬¬¬¬­¬¬­­¬­¬¬­­¬­­­­­­¬¬­¬­¬­¬¬­­¬¬¬¬¬¬­¬­¬­­¬¬¬¬¬®®®®®®®®®­­­®®­­­­­­­­­¬­¬¬­¬­­¬¬­­¬¬¬¬­¬¬­¬­¬¬­­¬¬¬¬¬¬¬­¬¬­¬¬­­¬¬¬¬¬­¬¬­­­¬¬­­¬­¬­­¬­¬¬¬¬­­¬¬¬¬¬¬¬¬«««««««««¬¬¬­¬¬¬¬­¬¬­¬¬¬­­®®®®­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬¬­¬­¬­¬­¬­¬¬¬¬­­­­¬¬¬¬­­¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­¬®®®®®®¬¬®®®®­­®­­­­­­­­­­­­¬¬­¬¬­¬¬­¬¬­¬­¬¬­¬¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬¬­­¬¬¬­­­­¬­­­­¬¬¬­¬¬¬¬¬¬¬¬¬««««««««««¬­¬¬­­¬¬­¬­¬¬®­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­¬¬­¬¬­­­¬¬¬­­­­¬¬­­­­­­­¬­¬¬¬­¬­­¬¬­¬­¬¬­¬¬¬­¬¬®®®®®®®¬¬®®­­­¬­­­­­­­­¬¬­­­­­¬­­­­­¬¬¬¬­¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­­­¬¬¬¬­¬¬­­­­­­­­¬¬­­¬¬¬¬¬¬­¬¬¬¬¬¬¬¬««««««««¬¬¬¬¬­¬­¬¬­¬¬­­¬­­­®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬­¬¬¬¬­¬¬¬­­¬¬¬­­­¬­­¬­¬¬­­¬­¬¬¬¬­¬¬­¬¬­¬¬¬­­­¬­¬¬®®®®®®¬¬®­­¬­­­­¬¬­­¬¬­¬­¬¬­­­¬­­¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬­­­­­¬¬­¬¬­¬­­­­­­­­­¬­­­¬¬­¬­¬­¬­¬««««¬¬¬­¬¬¬¬­¬¬¬¬¬­­¬¬­­­­®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬¬­¬¬­¬¬¬¬¬¬¬¬¬­®¬¬­¬¬­¬¬¬¬­¬­­¬¬­­¬­¬­­¬¬­­¬­¬¬®®®®®®®®®®­­®®®­­­­­­¬­­­¬­¬¬¬­­­¬­¬¬­¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬­¬¬­­­­­­­­­­­¬¬­­¬­¬¬­¬¬¬¬¬¬«««««««¬¬¬­¬­®¬¬­¬¬¬­­¬­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬­­®­­­¬¬­¬¬­¬­¬¬­¬¬¬­¬­¬¬­¬­¬¬¬¬¬­­¬­­­­­­¬¬¬­¬¬­¬¬­­¬®®®®®®®®®­­­®®®®­­­­­­­¬®­­­­­­­­­­­­­¬¬­¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬­¬¬­­­­­­­­­­­¬¬­¬¬­¬­­¬¬¬¬¬¬«««¬¬¬­­¬¬¬¬¬­¬­­¬¬¬¬®­¬¬­­­­­­­­­­­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®¬¬­­¬­¬­¬¬¬¬­¬¬¬­¬¬­­­¬¬­¬­­¬­¬¬­¬¬¬­¬­­¬­¬¬­¬¬­­­­¬¬¬­®®®®®®®®®­­®­®­®®­¬­­¬­®®­¬­­­­¬¬­­¬­¬­­¬­­¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬­­¬¬­¬¬¬­¬¬¬¬­­­­­­­­¬¬­¬­¬­¬­¬¬¬¬¬¬«««««¬¬¬¬­¬¬­¬­®­¬­­¬­­¬­­­¬­­­­¬­­­®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­¬¬­¬¬¬¬­¬­­¬­¬­¬¬­­­¬¬¬­¬¬¬­­­­¬¬­¬¬¬¬¬­¬®®®®­­­­­­­®®­­­­­­­­­­­­­¬¬­¬¬­¬¬­­¬­­¬¬­­¬¬­¬­¬­¬¬­¬¬¬­¬¬¬¬¬¬¬­¬­­¬­¬­¬­­­¬¬­¬¬¬¬¬­¬¬¬¬¬­««¬¬¬­¬­¬¬­¬¬­¬¬¬¬­¬­­­¬¬¬­­­­­­­­®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬¬¬¬­¬¬¬¬­­¬­¬­¬­­¬¬¬­¬­¬­¬­­­¬­¬¬¬¬­¬­¬¬­¬¬­¬¬¬­¬®­­­­­¬­­­­­®­­­­­­®­­­­­­­¬¬­¬¬¬¬­¬¬­­¬¬­¬¬¬­­­¬¬¬­¬­¬¬¬¬­¬¬¬¬­¬­¬¬­­­­¬¬­­¬¬¬­­­­­¬¬¬¬¬­¬¬«««¬¬¬¬¬¬­¬¬­¬®¬¬¬¬¬¬¬¬¬¬­®­­®®®®®®1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬®­­¬¬¬¬¬¬¬¬¬¬¬­­¬­¬­¬¬­­­­¬¬­¬­¬­¬¬­¬­¬¬¬¬¬­¬­­­¬¬­¬®®®®®­­¬­­­®­­®­­­¬­­­­®­­­­­­­¬­¬­¬­­¬¬­¬­­­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬¬­¬­­­­¬¬­¬¬­­¬¬­¬¬­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬­­¬­­­­­¬¬­­­®­®®®®¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬­­­­¬¬¬¬¬¬¬¬¬¬¬®¬¬­¬¬¬­¬¬¬­¬¬­­­­¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­¬¬¬­®®®®®®­¬­­­®®­¬­¬­¬­­­­­¬­¬­­­­¬¬­¬¬­¬¬¬¬¬­­¬­¬¬¬¬­¬¬­¬¬¬¬¬­­­¬¬¬­¬¬¬­¬­¬¬­­­­­¬¬¬¬¬¬¬¬¬¬«««¬¬¬¬¬¬¬­¬¬¬­¬­­¬®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®¬¬­­¬­­­­¬¬¬¬¬­¬¬¬¬¬¬­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬­¬¬­¬­¬¬¬¬­¬¬¬¬­¬®®®®®®­­­­­­­¬¬¬­­®®®®­­­­­­­¬­®­­­­­¬­¬¬¬¬­­­¬­­¬¬¬­¬¬¬­­¬¬­¬¬­¬¬¬¬­¬¬­¬¬¬¬­¬¬¬¬­­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬««¬¬¬¬­¬¬­¬­¬­­­­­¬®®®®®®®¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬¬¬­­¬­­­­¬¬­­­­¬­¬­¬¬­¬­¬­¬¬¬¬­­­¬¬¬¬­¬¬­­¬¬¬¬¬¬­¬¬¬­®®®­­­­­¬­­­¬­®®®®®®­­­­­­­­­­­­­­­­¬¬­¬¬¬¬­­¬­¬¬¬­¬¬¬­­­¬¬­­¬­¬¬­¬¬¬­¬¬­¬¬¬¬­¬­¬¬­­¬¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬­¬¬­¬­¬­¬­®­®­­®®®®®®®®®¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬­­¬¬¬­¬¬¬¬¬­­¬¬­¬­¬¬­¬­¬¬­¬­¬¬¬¬­¬¬­¬¬¬¬¬­¬¬¬¬­¬®®­®¬¬¬¬­®®®®­­­­­­­­­­­­­­­­¬¬¬¬¬­¬­­­­¬­¬¬¬¬¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬­­¬¬­¬¬­­­¬¬­¬¬¬¬­­¬­­¬¬­¬¬¬¬¬¬¬¬¬«¬¬¬¬¬¬¬¬­¬­­¬¬¬­­®®®®®®¿1111®­¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬¬¬¬­¬­¬­­¬¬­¬¬­¬¬­¬¬¬¬¬¬­­¬¬­­¬­¬­­­¬­¬¬­¬¬¬¬­¬¬¬®®®®®­­­­­­¬¬¬¬®®­®®®®®­­­­­­­­­­­­­­­¬¬­¬¬­¬¬­­¬¬­¬­¬­¬¬¬¬­¬­¬¬¬¬¬¬­¬¬¬­¬¬­¬­¬¬¬­¬­¬¬­­¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬­­¬­®®®®®®®®®111111111111®¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­¬¬­­­­¬¬¬­­­¬¬­¬­¬¬­¬¬­¬¬¬¬¬¬­¬¬¬­­¬¬­¬¬­­­¬­¬­¬¬­¬­¬­­®®®®®­­¬­¬¬­­­­®®®­¬­­®­­­­­­­®­­­¬¬¬¬¬­¬¬¬­­­­¬­¬¬­¬¬­¬­¬­­­¬­¬­¬­­­­¬¬¬­¬­¬¬­¬­¬¬¬¬­¬­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­¬­¬­®®®®®®®®®®®®®®®®®111111111¿1111111111111®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­¬­¬¬­¬­­¬¬­¬­¬¬­¬­­¬¬­¬­­¬­¬­­¬¬¬­­¬¬­­­¬­¬¬¬®®®®­­­­¬¬¬­­®®­­­­­­­­¬­­­­¬­¬¬­¬¬­¬­¬­­¬¬¬­­¬¬­¬¬¬¬­­¬­­¬¬­¬¬­¬¬­­¬­­¬­­¬­¬¬­¬­­¬¬­­¬­­¬¬¬¬¬¬¬­­¬«««¬¬¬¬¬¬¬­¬¬­­­¬¬¬­®1111111111111¿11¿111111111111111111111111111®®®®®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­¬­¬¬¬­­¬­¬¬­¬¬­­­­¬­¬¬¬­­¬­¬­¬®­¬­¬­¬¬­¬¬¬­®®®­­­­­­­­¬¬¬­­¬­®®®®­­­­­­­­¬¬­­­¬¬¬¬¬¬­¬­¬­­­­­¬¬¬­¬¬­­¬¬­¬¬­¬¬¬¬­¬¬­­­¬¬­¬¬¬¬¬­¬­¬­­­­­­¬¬¬¬¬­¬¬­¬¬«¬¬¬¬¬¬¬¬­¬¬­­¬¬¬­11111111111111111111111111111111111111111111111111111®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­¬­¬­¬­­¬¬¬­¬­¬¬­¬¬­­­­®­­¬­¬­¬­¬­¬¬®¬¬­­¬¬¬¬­­¬¬­¬¬­­­­­­­­­­¬­­­®®®®®®­­­­¬­­­­­­­­­¬­¬¬­¬­¬­¬¬­­¬­¬¬­¬¬¬¬¬¬­¬­¬¬­¬¬¬¬­­­­¬¬¬¬­­­¬¬­¬¬¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­­¬¬­­­­­­­111111111111111111111111¿111111111111111111111®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­¬­­®¬­­­¬­¬­­¬¬­¬¬­¬¬¬¬¬¬¬¬­®­­­¬­¬¬­¬¬¬¬­¬­¬¬¬¬­­­¬­¬¬­¬®®®®­­­­®­­¬¬¬­¬®®­­¬­­­­­­¬¬­­­¬­¬­­­¬¬­¬­¬­­¬­¬¬¬¬¬­¬¬­¬¬¬­¬¬­­¬­­­­­¬­¬¬­­¬¬¬­­¬¬­¬¬¬­­¬¬¬­¬¬¬¬¬¬¬­¬¬«««¬¬¬­­¬¬­¬¬¬¬­¬¬­®11111111111111®®®¿¿11111111111111111111®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­¬¬¬­¬¬­¬¬­¬¬¬­¬­¬¬­¬®¬¬­¬¬¬­¬¬­¬¬¬¬¬­­­­¬¬¬¬¬¬¬®®®®­­­­­®­­­­¬¬¬­­¬­¬­­­­­­­­­­¬­¬¬­¬­¬­­¬­­¬¬¬­­¬¬­¬¬¬­­­­¬¬¬­¬¬­¬¬¬­¬¬¬¬¬¬­¬¬­¬­¬­¬¬­¬¬­¬¬­­­­¬¬¬¬¬¬¬­¬¬¬¬¬¬«¬¬¬¬¬¬­¬­¬¬­­­­11111111111111®®®®®®®111¿1111111111111111111®®1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­¬­­¬­¬¬­­¬¬¬­¬¬­­­¬­¬­¬¬­­­­¬¬­¬­­¬¬­­®¬¬¬¬¬¬­®®®­­­­­¬­¬­®®®­­­­¬¬­­­­­­­­¬¬¬¬­¬¬­¬¬¬¬­¬­¬¬­¬¬­¬­¬­­¬¬­¬¬¬¬­¬­¬­¬­­­­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­­­¬¬¬­¬¬­¬¬¬¬¬¬¬¬«¬¬¬­¬­­­­¬­1111111111111®®®®®®11111111111111111111111111®®¿¿¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­¬¬­¬­¬¬¬¬¬¬­­­­­¬¬­¬¬­¬­¬­­­¬­­­­¬­¬­­®¬¬¬¬­­¬­®®®­­­­­¬­¬­¬­­­¬­­­­­¬­­­­­­¬­­¬­­¬¬­¬¬¬­­¬¬­­¬­¬­¬­¬¬­¬¬­¬­¬¬­­¬¬­­­­­¬­¬­­¬­¬¬­¬¬¬¬¬­¬­¬¬­¬­­¬¬¬¬¬¬¬¬¬¬¬¬««¬¬¬¬¬¬¬­¬­­¬­¬11111¿11111111111®111111111111111111111111111111®®®¿1¿¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®®®®®­®®®­­®®®®®®®®®®®®®­­­­­¬­¬­¬¬­¬¬­¬­¬­¬­¬¬­¬­¬¬­¬¬¬­¬­­­­­¬­­®®­®®®­®®­­­­­­¬­¬¬­¬¬­¬­­­­­­­­­®­­­­­­­­­­¬¬¬¬¬­¬­¬¬¬­­­­¬¬¬­­¬¬­¬¬¬¬­¬­­¬­­¬­¬¬­¬¬¬­¬­­¬¬­¬­¬­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­¬­­­­1111111111111111111¿111111111111111111111111111111111®®®¿11111¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­®­®®®®®®®®®­®®­®­®®®®®­­®®®®®®®®®­­¬¬¬­­¬¬­¬­­­­¬­¬¬­¬¬¬­¬¬¬¬­¬¬­­¬­¬­¬­­¬®®®®®®®®­­­­­­­­­­¬¬­¬¬®­®­­­­­®­­­­­­­­­­­­­­¬­­¬¬­­­¬¬­­¬­¬­­¬­¬­¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬¬­¬­¬¬¬¬¬¬­­­¬¬¬­¬¬¬¬­¬¬¬¬¬¬¬­­­¬­¬®111111111¿111111¿11¿11111111111111111111111®11111111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®­®®®®®®®­®®®®®®®®®®®®®­­®®®®®®®®®®®­­­­­­­­®­¬­­­¬¬¬­¬­­¬¬¬­¬¬­­¬¬­¬¬¬¬¬­­­¬¬¬¬¬­­­¬­®®®®­­­­­­­­­®®­®­­­­­­­­­­­­­¬¬¬­­¬¬­­¬­­¬­¬­¬­­¬¬­¬¬­¬¬¬¬­¬¬­¬­¬­¬¬¬­¬¬­¬­­­¬­­¬¬¬¬­­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­¬­­­®®11111®®®11111111111111111¿1111111111®¿11¿11¿11¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­®®®®®®®®®®­­®®®®®®®®®®®®®®®®®®®®­­­­­­­­­­­­­¬¬­¬­¬­¬¬­­¬¬­¬­¬­¬­­­­­­­¬¬­¬¬­­®®®®®®­­­­­­­­¬­­¬­­­­­®­®®­­­­­­­®­­­­­­­­­­¬¬­¬­­­¬­­­¬­¬­¬­¬­¬¬¬¬¬¬­¬¬¬¬­¬¬­­¬¬­¬¬­­¬¬¬­¬¬¬¬­­­¬­¬¬¬¬¬¬¬¬¬¬¬®¬­¬­¬¬­®­­­­­­¿11111¿®­­®1111111®®®1111111®®1111111®¿11¿1¿11¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­®®®®­®®®­®®®®®­®®®®®®®®­®®®®­®®­­®®®®®®®®®®®­®®®®®­­­­®­­¬­¬¬­­¬­¬¬­¬­¬¬­¬¬­­­¬¬­¬­­­­¬¬­¬¬­­­­­­­®®®®®­®­­­­®®­­¬­­¬­­­­­­­®­­­­­­­­­­¬¬¬­­¬­¬­­¬­¬¬¬­­­­¬¬¬¬­¬­­¬­¬­­¬­¬¬¬¬­¬¬­¬¬¬¬­­­¬­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­­­­­­­­11111®111¿1®®®®®1®®®®¿1111111®¿¿¿¿¿¿¿¿¿¿¿®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®­®®®­®­®­­®®®®®®®®®­­®®®®­­­­­­®¬¬­¬¬­¬­¬­­¬­­­­¬­­¬¬­¬­¬­¬­­­­­­¬­®®®­®­­­­­­­­®­­­­­­­­­­­­­­­­®­­­­¬¬­­¬­¬­­¬¬­­­­­¬­¬­¬¬­¬­¬­¬¬­¬­¬­­¬¬­¬­¬¬­¬­­¬¬¬­¬¬¬­­­­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­­­®®1111®®1111®®®11®®®®®®®®®®¿1111111®¿1¿11¿¿¿¿¿¿¿¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®®­®­­®®®®®®®®®®®­­­®­®®®­­­­­­­¬¬­­¬¬¬­¬­­¬­¬­¬¬¬­¬¬¬­¬¬¬¬­¬¬¬­­­­­­­®®®®®­­­¬­­­­­­­­­­­­­­­­­­¬­®­­­¬­­­­®­­­­­­­¬­¬¬¬¬­­­­¬¬¬­¬­¬­­¬¬­­¬¬­¬¬¬­­¬¬¬­¬¬­¬¬¬­¬¬­¬¬¬­¬¬¬­¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬¬­¬­­­­¬¬­®11®®®111111111¿®®®®®1111111®1¿¿¿111¿¿¿11¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®®®®­­®®®®­®®®®®®®®®®­®®®®®®®­­®­­®®®®®®®®®®®®®­®­­®®®®®­­­¬¬­¬¬¬¬¬­­­¬¬­­¬¬­¬¬­¬­¬¬­¬¬¬¬­¬¬¬­­¬­­­­­®®®®®®­­¬¬­­­¬­­­­®­­¬­­­­­­­¬­­­­­­­­­­­­­­­­­¬­¬¬­­¬­­­­¬­­­¬¬­¬­­­¬­¬­­¬¬¬­¬­­¬¬­­­¬¬¬­¬¬¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­­­­¬¬¬­11­®®®111111111111¿®®®®1111111®1¿11¿¿¿¿¿1¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®®®­®®­®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®­­­­®®®®¬­­­­­­¬­¬¬­­­­¬­­¬¬¬­¬­¬¬¬­¬¬­¬­­­¬­­­®®®®®®®®­­­­­­®­­­­®­­­­¬­­¬­­­­®­­­®­­­­­¬¬¬­¬¬­­¬­¬­­¬­¬­­­¬¬­­¬­¬­¬­¬­­¬¬¬­­¬¬­¬¬¬­¬¬¬¬¬¬¬¬­¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­¬¬¬¬¬®111®®®111111111111¿®®®®®1111111®¿1¿¿¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®­­®®®®®®®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­®®®®­®­­­­­­¬¬¬­­¬­­­¬­­­¬¬­¬¬­¬­­¬­­¬¬­­¬­®®®®®®®®­­­­­­­­®­­­¬¬­­­­­­­®­­­­­­­¬¬¬¬¬¬¬­¬­­¬­­­¬­¬¬­¬¬­­­­®­­¬­¬­¬¬­¬­¬¬¬¬­¬¬¬¬­¬­¬¬­¬¬­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­¬­¬¬­¬¬¬­®¿11¿­®®®11111111111111®®®®®1111111®®¿¿¿¿¿1¿¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®®®®®®®®®®®®®®®®­­®®­®­®®­®®­®®®®®­®®®®­®®®®­®®®®®­­®®®®®®®®®®®®®®®­­­­®®®®­­­­¬¬¬­¬­¬¬¬­­­¬¬­¬¬­¬¬­¬¬¬¬­¬¬­¬­­­­®®®®®®®®­­­­­®®­­­­®®­®­­­¬­®­¬­­­­­­­­­®­­­­­­­¬¬¬¬­­­¬­­­­­¬­­¬­¬­¬¬­¬¬®¬¬­­¬­¬­¬¬¬­¬¬¬¬¬¬¬¬¬­­­¬­­¬¬¬¬¬¬¬¬¬¬¬­¬¬­­­­­¬¬¬­¬¬­®11­®111111111111111111®®®®®®®®1111111®®¿1¿¿1¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®®­­®­®®®®®®®®­®­®®­®®­®®®­®®®®­­®®®®®­®®­®®®®®®®®­­­®®®®®¬­¬­­¬­­¬­¬¬­­­­¬­¬¬­¬¬­¬¬­¬¬­­­­¬¬¬¬®­­¬­®­®®®®®­­­®­­­­­­­­¬¬­­­­­­­­­­­®­­­­­­­­­­­¬­­­­¬­­­­­­­­¬­­­­¬¬¬¬­¬­­¬¬­­­¬¬­¬¬­¬¬­­¬¬¬¬¬­­­®¬¬¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬­­­­­­­¬¬­¬­­®®®®11®­­®111111111111111111®®®®®®®1111111®®¿¿¿¿¿¿¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­®®®®®®®®®­®­­®®­®®®®®®®­®®®®®®®®®®®®®®®®®­­­­®®®®®®®­¬­¬¬¬¬¬¬¬­¬¬­¬­­¬¬­¬¬­¬¬¬¬­­¬¬­¬¬¬­­­­­­­­®®®®®®®­­®­­­­­­®®­¬¬­­­¬­®®®­­­­­­­­¬¬¬¬­¬¬¬¬¬­¬­­¬¬­¬­¬­­­¬­¬­­¬¬­¬­­¬¬­¬¬­­¬¬­­¬¬­­¬¬­­¬¬¬¬¬¬¬¬­¬­­¬¬­¬¬¬¬¬­®®®111®®®1111111111111111111®®®®®1111111®¿¿¿¿¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®­®®®®®­®­®®®®­®­®®®®®®­­®­­®®­®®®®­®­­®®®®­®®®®®®®®®®®®®­­¬®­¬¬¬­¬¬¬¬­­¬­¬¬­­¬­­­¬­­¬­¬­®­¬­­­®®®®®®®®­­­­­­­®®®®­­¬­­­¬®­­­­­¬­­®­­­­­­­®­­­­¬­­­¬­¬­¬¬¬¬¬¬­­­¬¬­­¬¬­¬­­¬­­¬¬­¬¬­¬¬¬¬¬­¬­¬­¬¬­­¬¬¬­¬­­¬­¬¬¬¬¬¬¬¬­¬­¬¬­¬¬­¬¬­®®®®1111¿11111111111111111111111®®®®®1111111®¿¿¿¿¿¿¿¿¿®®®¿®®­®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­®­­®®®®­­®®­®®®®®®­­®­®­­®­­®®­­­®­­®®­®®®®®®­®®®®­­­­­­­¬­­­¬¬¬­¬­­¬­¬¬­­­­¬­¬¬­¬¬®¬­­­¬­­®®®®®®­­­­­­®­®®®­­¬¬­®­¬­­­­­­­­¬®­­­®®®®­­­­­­­­¬­­¬­¬¬¬¬¬­¬¬­¬¬¬­­¬¬­­­¬¬­¬¬­¬¬­­¬­¬­­¬¬­¬¬­¬­¬­¬­¬­­­¬­­­­¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬­¬­­¬¬­®®®®11111111111111111®111®®®®®®®1111111®¿¿¿1¿¿¿¿®®®®¿¿®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®­®®®®®®®®®®®®®®®­­®­­®®®­­®®®®®®®®®®­®­­®­®®®®®­­®­®®®®®®­®®®®®®­­­­®¬¬­­­­¬­¬­¬­¬¬­¬­¬­¬¬­¬¬­¬­­¬¬­­­­­­­®®®®®®­­­­­­­­®®­­­­­¬¬­­¬¬­®¬­­¬¬®®­®®­­­­®­­­­­­­­¬¬­¬¬¬¬¬¬¬­­¬­­­¬­­¬­¬¬­¬¬¬­¬¬­¬­¬­¬¬­­¬­­­¬­¬­¬­¬­¬­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­­­­¬­¬¬­­®®1111111®®®®1111¿®®®®®®®®®®®1111111®®®¿¿11¿1¿¿¿®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®­®®®®®®®­®®®®®­®®­­®­®­­®­­®®®®®®®®­­¬­­­­­­­­¬¬­­¬­¬¬¬¬­¬¬¬­­¬¬¬­¬¬­¬¬­¬­¬¬­¬­¬¬¬¬­­®®­®®®­­­­­­­®®®®­­®¬­­®¬­­­­­­­®®®®®­­®­­­­­­®­­¬­­¬¬­¬­­­­¬¬­­¬­­­­¬­­¬­­¬¬¬­¬¬¬¬¬¬­¬­­¬­­¬¬¬¬¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­­¬¬­¬¬­­¬¬11®®®®®®®®®®111®®®®®®®®®®1111111®®®1¿¿11¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­®®®­­®®­®®®®®­®­®­­­®®­­­­­­­®®®®®­®­¬­¬¬¬¬¬­­­­¬¬¬¬­­­¬¬­­¬¬­¬¬¬¬¬¬­¬­­¬¬­¬¬¬­¬¬¬­­­­­®­®®­­­­­®®®®®®­­­®®®¬®®®¬¬¬­®®®®­­­­­­­­­¬¬­­­­­¬­¬¬­¬­­­­­¬­¬¬¬­¬¬­¬¬­­­­­­¬­¬¬­­¬­¬¬¬¬­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬¬­¬¬¬¬¬­­¬¿11®®®®®®®®®®11®®®®®®®®®®®1111111®®1¿1111¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®®®®®­®­­®®®®®®­­®­­®­®­®®­®®®®­®®®®®®®®¬­¬¬­­¬¬¬­­¬­­¬¬­­­­­¬­¬­¬¬­¬¬­­¬¬­¬¬­¬¬­¬­­¬­­­­­®®®®­®­­­­­­­®®®®®®®®®­­­®­®®®®®¬¬­­­®­®®®®®­­­­­­­­­­­­­­­¬­­­¬¬­¬¬­­­­¬­¬­¬¬¬­¬­¬¬¬­¬­­¬­­­¬¬­¬¬¬¬¬¬¬­¬¬¬¬¬¬¬­¬­¬­¬­­­­­¬¬¬­®1®®®®®®1®®®®®®®®®®1111111®®®¿1¿¿¿¿¿1¿¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®®®®­®®®®®®­­®­­®­­®­®­­­®®®®®®­®®­®­­¬¬­­­­®­¬¬¬­¬¬­­­­­­¬¬­­­­¬­¬¬­¬¬­­¬­¬¬­¬¬­­­¬¬­­­¬­®®®­­­­­­­®®®®®®®®®®®®¬¬­¬¬¬®®®®¬¬­¬­­­®®­­­­®­­­­­­­­­­­­¬¬­­¬­¬¬­­­¬¬­­¬¬¬­¬­¬­­¬¬­­¬¬­­­­­­¬­­­¬­­¬¬­­¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­­¬­¬¬¬­¬¬­¬¬1®®®®®®®®®®®®®®®®®1111111®®®®®¿¿¿¿¿¿111¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®­­®­®®®®®­­®­®®­­­®®®®®®®®®®®¬¬­¬¬­­­¬¬¬¬­­¬­­­­­­­¬¬­­­­­­­­­­¬¬­¬¬¬¬¬¬­¬­­®­®®­­­­¬­­­®®®®®®®®®®®­­­¬¬¬­­®®®®­¬¬¬­®­®­­­®­­­­­­­­­­­­¬­¬­¬¬­­­­¬­­¬¬­­¬¬­¬¬­¬­¬¬­¬¬­­­­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬­­¬­­­­¬¬­­­¬­®11®­®®®®®®1®®®®®®®®¿111111®®®®®¿¿¿1¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®­®®®®­­®­®­­­­®­­®­­­®­®®®®®®®®®®®­­¬­¬­®¬¬¬¬¬­­­­­¬­¬¬¬­¬®­­¬¬¬¬­­¬¬¬­­¬¬¬¬­­¬­®®®®­­­­­­­­­®­­­®®®¬¬­¬­®®®¬¬¬­­­­®­®­­­­­®­­­­¬­­­­­­¬­¬¬­¬­­­¬¬­­­­¬¬¬­­¬¬­¬­¬¬­¬­¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬¬­¬­¬¬­¬­¬®11¿1®­®®1®®111111®®®®®®®®111111®®®®®¿¿¿¿¿1¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®­®­­®­­­®­­®­­­®®®®®®­®®®®®¬¬¬­¬­­¬¬¬¬­­­­­­­­­¬­­­­¬­¬¬­¬¬­¬¬­¬­¬­­¬¬¬¬¬­­­®®®®­­­­­­­­®®­­­®®®®®®®¬­¬¬­¬­­®®®®®­­¬¬¬­¬­¬¬­®®®¬®­­­®­­­­­­­­­­­­­­¬¬­¬­­­­¬­¬­­­¬­­­¬­¬­¬¬­¬¬¬¬­¬­®¬­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬­¬¬­¬¬­¬­­­®1111­1®®11111111®®®®®®®111111®®®®®®11¿¿1¿¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®­®®­®®®®®­®­­®­­­®­­®­­®­®®®®®®®®®®®®­®®®­¬¬­¬­­¬¬¬¬­¬¬­¬­¬­­­­­­­­­¬¬­¬¬­¬¬­¬¬­¬­¬¬­¬­­­­­­­­®®®®®®®­­­­®®®®­®¬­¬­¬¬­­¬®®®®­­­­­¬­¬­®®®®®®®®­­­¬­­­¬¬­¬­¬¬¬¬­­­­­­¬­­¬¬­¬¬¬­¬­¬¬­­¬­­­®¬­¬­­­¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬­¬­­¬­¬­¬­®1111­­®11®¿11111111®®®®®111111®®®®1¿1¿1¿¿1¿¿¿1¿®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®­­­®®®­®­­®­­®®­­®®­®®­®®®®®­­­­­¬­®­¬¬­¬­¬­­­­­­¬­­­­¬¬¬¬­­¬¬­¬¬¬­¬¬­¬¬¬¬­­­­¬¬®®®­­­­­­­®¬­­­¬¬­­­®®®®­­­­­®®®®­®®­®­­­­­­­­­­­­­­¬­¬­­­¬¬­­¬­¬­­­­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­­­­­­­¬¬­¬¬­­¬­¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬­¬­­­¬¬­­­­­¬­¬¬¬¿11111­­11®111111111®®®®®®®®®®®®®®®¿11¿¿111¿¿¿¿111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­®­®®®®®­®­­®®®­­®­®®­®­­®®­­®­®®®®®¬­­¬¬­­¬­­¬¬¬­¬­­¬­­­­¬­¬¬¬­¬­¬¬­¬¬­­¬­®®­­®­­¬­­­­­¬­­¬¬­¬­¬¬­¬­­®®®®­­­­­­®­®®®­­­­­­­­¬­­¬¬­­¬¬­¬¬¬­¬¬­¬­­­­¬¬­¬­­¬­­­­¬­¬¬¬­­­­¬­­¬¬¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬­­¬­¬¬­¬­¬­¬¬­¬¬­¬­¿11111­­­11111111111®®®®®1®®®®®®®1111111¿¿¿¿11¿®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®­®®®®®­®®®®®­®­®­­®­­®­­®­­­­®®®®®®®®®®®­¬­¬­­­¬¬¬­­­¬­­­¬­­¬­­­¬¬­­¬­¬¬­¬­¬¬­¬¬­¬­­¬­­­®®­®­­­­­­­­­¬­¬¬­­¬­¬­­­­­­­­­­­­­®­®®®®®®­­­­­­­­­­­­­­­¬­¬¬¬­¬­¬¬­¬¬­¬­¬­¬­®¬¬­¬¬­­­­­¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­­­¬¬¬­­¬¬­¬­­¬¬­­¿1111111®®1111111111®®®®111®®®®®®®¿¿¿11111111¿¿¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®­®®®®®­®®®®®®®®®®­®®®®­®­®®®®®®®®­­®­­®­­®­­®®®®®®­®®®¬­¬­­¬¬¬­­­­­¬­­­­¬­¬­­­­­­­­­­¬¬­¬¬¬­¬¬¬¬¬­­¬­­¬­­®­­­­­­­­­­­­­­­®®¬¬­¬¬­­¬­­®¬­®®­­­­­®­®®®®®®­­­­­®­­­¬­­­­­­­¬­¬­­­­¬­­­¬¬­¬¬­­­­¬­¬¬­¬¬­¬¬­­­­­­­­­¬¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬­¬­¬­¬­¬­­­­­¬­¬¬®¿¿111¿­®1111111111111®®111®®®®®®1¿1¿¿1111111¿¿1¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®­®­®®®®®­®®®®®®®®®®­­­®­­­­­­®­­®®®®®®®®®­¬¬¬¬¬¬¬¬¬¬­­­­­­­­­­­­¬­¬­­­­¬¬­­­¬¬­¬¬­­­¬¬¬¬¬­­­­®­­­­­­­­­­­­­­®­­¬­¬­¬­­­®­¬¬¬¬­­®®®®®®®®®®®®®®­­­­®­­­­­­¬¬­¬®­¬­¬¬­¬¬­¬­­¬¬­¬¬­­¬­¬­¬¬­¬¬¬­­­­­­¬¬¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­¬¬¬¬¬­­¬¬¬­­¬­­¿1111­®1111111111111®®®®®®1111®®®¿11¿1111¿11¿11¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®®­®®®®®®­®­­®­®­­­­­®®­®­®®­¬¬¬¬­¬¬¬¬¬¬­­­­­­¬­­­­­­­­­¬¬¬­¬¬¬­¬­¬¬­­¬¬­­®®®­­®­­­­­­­®­®­­­¬­¬¬­®®­¬­¬¬­®­®®®®­®®®®®®®®®®®®®®®­­­­­­­­­­®­¬­¬¬­¬­­­¬¬¬­¬­­­­¬­­¬­¬¬­¬­¬¬¬­¬­­­¬­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬¬­­¬­¬¬­¬¬­¬¬¬­¬¬­¬¬®¿1¿11­­®111®1111111111®®®®1111®®®®11¿1111¿11¿¿¿¿1¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­®­®®®®­®­­­­®®®®­­®­­­­­®®®®®®­­¬¬¬­¬¬¬¬¬¬¬¬­¬¬¬­­­­­¬¬­­­­­­¬­¬­­­¬­­­­¬­­¬­®­­­­­®­®­®®®­­­¬­­¬®­®­¬­¬­¬¬®­­­­®­®®®®®®®®®®®®®®­­­­­®­­­­­­¬¬­­­­¬¬­¬¬¬­­¬¬­¬¬¬­­¬¬­¬¬­¬¬­¬­¬­­­®­­¬¬­¬¬­­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­¬¬­¬­¬­¬¬­¬­­¬¬¬¬¬®11¿1­®111®1111111111®®®11111®®®1¿11¿¿11¿¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®­®®®®®®®®®®®®­­®®®­®­®®­®®®®®®®®®­­­¬¬¬¬¬­¬­¬¬­¬¬¬­­­­­¬­­­­­¬­¬¬¬¬­¬¬­¬­­­­­¬­­­®®­­­­­®­®®¬­­¬­¬¬­­­­¬­­­­­­­­®®®®®®®®®®­­­­­­­­­­­¬¬¬¬­­­¬¬­­­¬­­¬­¬­¬¬­¬­­¬­¬¬­­­­­­¬­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¬¬­­¬¬¬­¬¬­¬¬­¬¬®1­®1111111111111®®®®®11111®¿11111111¿¿¿¿1111¿¿¿®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­®®­­­­®­­­­­¬­¬¬­¬¬­¬¬¬­­­­­­­¬¬­­­­­­­¬¬¬­¬¬¬­­¬¬­­­®®­­­­­­­­­­®®®­­­­¬­­­¬­¬¬­­¬­®­¬¬­¬¬¬­­­­®®®®®®®®®­­­­®­­¬­­¬¬¬­­­¬­¬­¬­¬¬­­­­­®­®¬­¬¬­¬­¬¬¬­­­¬¬¬­¬¬­¬¬­¬¬¬¬­­¬¬¬­­­­­­­­­¬¬¿1­¬­®111­­1111111111®®111111111111111¿111¿111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®®®®­­®­­­­­­­­­­­­®­­­­­­­­¬¬­¬¬­¬­¬­¬¬­¬­­­¬¬­­­­­­¬­­­­¬¬­¬­­­¬­­­­¬­­­­­­­­¬­¬­¬¬¬¬¬¬­¬­­®®­­­­¬­¬­®®®®®®®®®®®­­­­®­­­¬­¬­¬¬­¬¬­­­­¬­­­¬­¬¬¬­­­®®®­­¬­­¬­¬¬¬¬¬¬¬­¬¬¬­­­¬­¬­¬­¬­­¬¬¬­­­­­­­­­­­­¬­®®®®¿­­®111­­­1111111111®®®11111111111111¿¿11¿1¿11¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­­®®®®®®­­­­­­­­­®®®­­­­­­¬­­¬¬¬¬¬¬­¬¬¬­¬¬¬­¬¬¬­¬¬¬¬­¬­¬­¬­¬¬¬¬­®­­­­¬­­­­­®­­­­­®­¬­¬¬¬­­®­­¬¬­­®®®­¬­¬­­­­®®®®®®®®®®®®®®®®­­­­¬­¬¬­¬¬¬¬­¬¬­¬¬­¬¬¬­¬­®­®¬¬­­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­­¬¬¬¬­­¬­­­­¬­­­­¬¬®®®1­­11­®111111111®11111111111111¿11111¿¿1¿¿1®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­®®®®®®®­­®­­­­®­­­­®­®®®­­­­­­¬­­¬¬­¬¬­¬¬­¬¬­­­¬­¬­­¬¬­¬¬¬­­­¬­¬­­¬­­­¬­­­­­­­­­¬­­¬¬­¬­¬­­­­­­®®­¬­¬­­­®®®®®®®®®®®®®­­®­­­®­­¬­­­¬¬­¬­¬¬¬¬­¬­­­®®®®®®®­¬­¬­¬­¬­¬¬¬¬¬­­¬¬¬­¬¬­¬¬¬¬­­­­­¬­­®®1­­­­11®111111111®®1111111111111111111¿11111¿¿¿¿¿¿®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®­­­­­­­­­­­­­­­­®®­­­¬­¬¬­¬­¬¬¬­¬­­­­­­­­­­¬­¬¬¬­­­­­­­­­­­­­­­­­­­®­­­­­­­¬¬¬­­­­­­­®¬­®®®®®®®®®®®®®®®®­­­­®®­­¬¬¬­¬­¬¬­¬¬¬¬¬­­¬¬­­­­®®®®®®®­¬¬¬¬­¬­¬¬¬­¬¬­¬­­­­¬­­¬­¬­¬­­­¬¬­­­­­®­­­­­®®®1­­­®11­111111111®®111111¿¿1¿11111¿¿1111111¿¿¿1¿¿¿1¿®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®­­®­­­­­­­­­­®®®®­­¬¬¬­¬­¬­­­­®­¬­­­­¬¬­­­¬­¬¬­¬¬­­­­­­­­­­­®®­­­®­­­­­­­­¬­¬­­®­¬­¬­­­­®®­­­®®®®®®®­®­­­®®®­¬­­­­¬¬¬¬¬­¬¬­¬­­¬­­¬­­­­®®®¬¬­¬¬­­¬¬¬­¬­­­¬¬¬¬¬­¬¬­¬­¬¬¬¬¬­­¬­­­­­¬­¬­®11­11®1111111®®®111111®¿11111111¿1111111¿1¿¿1¿11¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®­®®®­®®­­­­­­­­­­­­­­­­­®®®®­­­­¬¬­¬¬­¬¬­­­­­­¬­­­­­­¬®­­¬­¬¬­­­­­­­­¬­­­­¬­­­­­®®­­­­­­¬¬­¬­¬­¬®­¬­¬¬­­­­­­­­®®®®®®­®­­®­­­­¬¬­¬­­­¬­­¬¬­¬­­¬­­¬­­­®®®®®®¬­¬¬­¬¬­­¬­­¬¬­¬¬­­¬¬­¬­­¬­¬¬¬­¬­­­­­­­­¬11­­­­®1®­­1111®®®111111®1111111111¿1111¿¿¿1111¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­®­­­­®­­­­­­­­®®®®®­­­­¬¬­¬­¬¬­¬¬­­­­­­­¬­­­¬­­­­­­¬¬­¬­¬­­­­­­­­­¬¬¬¬­­­­­­­­­­­¬¬¬¬­¬­­¬­®­­­­®­­­­®®®®®®­­­­­­­­¬¬¬¬¬¬­­­¬¬­¬­¬¬­¬­¬¬¬­­­®®®®®¬¬­¬­¬­­¬­­­¬¬­¬¬­¬­¬­¬¬¬¬­¬¬­¬­¬­­­­­­­­­­­­¬­­­®®­¬¬¬11®®®®®1¿11111111111¿¿1¿¿11¿¿¿11111¿11¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­­®­­­­­­­­­­­®­­­­­­®®®®­­­­¬­¬­¬¬¬¬­¬¬­¬­­¬­­­¬¬¬¬¬¬¬­¬¬­­­­­­­­­­­­­¬­­­­­®­­¬¬­¬­¬­®­­­­­­®®­­­®®®®®®®®­­­­­­­­­¬¬­­­­¬­¬­¬¬­¬¬­¬¬­­­­­­®­¬­­¬­­¬­¬­¬­¬¬¬¬­¬­­¬¬­­­­¬¬­­¬­¬­­­­­­­­­®1¿®®­¬­­®111­®®®®®®11®®11111111111111111¿1111111111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­®®®®®®®®­­­­­­­­­­­­­­­­®®®­­­¬¬­¬¬­¬¬¬­¬¬­¬¬¬¬­­­­­¬¬¬¬­¬¬¬­­­­­­­­­­­­¬­®­­­­¬¬¬¬¬­­¬­­­­­­­­­­®®®®­­­­­®®®®®®®®®®®®­­­­­­­¬¬­¬­­¬¬­¬­­¬­¬­­¬­¬­­­­®¬¬¬¬¬­¬¬­­¬¬­¬­­­¬¬­¬­¬­¬¬¬­­­­­­­­­­­­­11®®­­­­®111­®®®®®®11®11111111111111111111111111®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®­®­­®­®®­®­­®­­­­­­­­­­­­­­­­­­­®®®¬¬¬¬¬¬­­­­¬¬­­­­¬­¬¬¬­­­¬¬¬¬­­­¬­­­­­®­­­­­­­®¬­­­­®®­­­­­­¬¬­¬¬¬¬®­­­­­®®®­­­­®®®®®®®­­­­¬­¬­­­­­¬¬­¬¬­­­­­¬­­­­­­­®®®®¬¬­¬­­­¬­­­¬¬­¬¬­¬­­­¬¬­¬¬­­¬¬¬¬¬¬¬­­­¬­­­­­­­­­­­­®11®­­­­®11®®®®®®®®®11®111111111111111111¿111¿11111111®®®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­­­­­­­­­­­­­®­®­­¬¬¬­¬¬­­­­­­­­­­­­¬¬¬¬­¬¬¬¬¬­­¬¬¬­­­­­®­­­­­­­­®®®®­­®­¬­­­®­­­­­®­®®®®®­®®®®®®®­­­­­­­­¬¬­¬¬¬¬­­­¬¬­¬¬­¬­­­¬¬¬­­­­­®®®®®­­­¬­¬­¬­¬¬­¬¬­¬¬­¬­­¬¬¬¬­¬¬­¬¬­¬­¬¬¬¬¬­¬­­­®­¬®111­­­®®®®®®1®11111111¿111111111111111111111¿¿®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®­®®®®®­­­­­­­­­­­­­­­®®®­­­¬¬­¬¬­­®­¬¬­­­­­­¬¬­¬¬¬¬­­­­¬¬¬­­­­­­­­­­­­­®­®®­­­¬­¬­­­­®¬¬¬®­­®®®®®®®­®®®­­­¬¬­¬­¬­¬¬¬¬­¬¬­¬¬­¬¬­¬­­¬¬­­®®®­¬¬­¬­¬­¬¬­­¬­¬­¬¬­­¬­¬­¬­¬¬¬¬¬­­®­­­¬¬®®111®®®®®®¿1®®®®®®®®®®®11¿11111111111¿1111111111111¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­­®­­­­­­­­­­­­­­­­­¬­®®®®®®­­¬¬­¬¬­¬­­­¬­¬­­­­­­­¬¬¬¬­­¬­­­¬­­­­­­­­­­­¬­­¬®®®®®®®­­¬­­­­­­¬­¬­­®­¬­­®­®®®®®®®®®®®­­­­¬¬¬¬­­¬­¬¬­¬¬­¬¬­¬­­¬­¬®­­¬¬­¬­¬­­­­¬­­¬¬­¬¬­¬­¬­¬¬¬¬¬¬¬¬¬¬­¬¬¬¬­­­­­­­­­®®1111111111¿1111111111111¿1111111111¿®®®11111111111¿¿111¿1111111¿¿11¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­®®®­®­­­­­­­­­¬­­­­­­­­­®®®®®®®¬¬­­¬¬¬¬­­¬­­¬­­¬­­¬¬¬­¬¬­¬­¬­­­­­­­­­­­¬­­­­­­­®®®®®®­®­­­­¬¬­¬¬­¬­®­­­­®®­®­­®­®®®®®®®­­­­­­­¬¬­¬­¬¬­¬¬­¬¬­¬¬¬­¬­­­­¬­­­®®¬¬­¬¬¬¬¬­¬¬­¬­¬¬¬­­¬¬­­¬¬¬¬­¬­­¬¬¬­­¬­®­­­­­­­¬¬®®1111111111111111111111111111111111111111111111®®111111111¿111111¿¿11111¿¿¿¿®®®®®®®®®®®®®®®®®®®¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®­­­­­­­­­­­­­­®®®®®®­­­­¬­¬­¬­¬¬¬­¬¬­­­­­­¬¬­¬¬¬¬­­­­­­­­­­­­­­¬­®®®®­­­­­¬­­­­­¬¬®­­­®®­®®®®®®®­­­­­­­¬¬¬­¬¬¬¬¬¬­­¬¬­¬­¬­­­¬­­­­®®®­®¬¬¬¬­­¬¬­¬­­­­­¬¬­¬­¬¬¬¬­¬¬­­­­­­­­­­¬­®®®®¿11111111111111111111111¿111111111111111111111¿®1111111111111111¿111111¿¿¿11®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­®®¬¬¬¬­¬¬¬­¬­¬¬¬­­­­­­­­­­­­­®®®®®­­­¬­­­­¬¬­®®¬­­­­­­­­­­®­¬¬­¬­¬­¬­¬¬¬¬¬¬­­­­¬¬­¬¬­¬¬­­¬­¬¬­¬¬­¬­®®®®­­®®­¬­­­¬­¬¬­­¬­¬­¬¬­­¬­­¬¬­­¬­¬­­­­®¬¬­®®¿¿11111¿111¿1111111111111111111111®®111111111¿111111111111¿¿¿¿¿®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®®®®­­­®®®®®­­­­¬¬¬­¬¬¬¬¬¬­¬¬­­­­­­­­­­­­­­­­®®®®®®®®­­¬¬­­­­­¬­­­­­­­­­­­­­­­­®­­­­­¬­­­­­¬¬­¬¬¬¬¬¬¬­­¬¬¬­­¬¬­¬­¬¬­¬¬­¬®®­­­­­­®¬¬­¬¬­¬­¬­¬¬­¬¬­¬¬­¬¬¬­¬­­­¬­­¬¬­¬­¬­­­­­­­­­®®®®®®®®®¿111®®¿1111111111111111111111®111111111¿1111111111111111¿¿1®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­¬­­®®­­­­­­­­¬¬¬¬¬¬­¬¬¬¬¬­¬­­­­­­­®®®®®®®®®®­¬­¬­­­­­­­­­­­­­­­­­­­­­­¬­­­¬¬­­­¬­­¬¬¬¬­¬­¬­­¬¬­¬¬¬¬¬¬­¬¬­¬­¬¬­®®­­­­­­­­­­­¬¬­¬¬­¬¬­­¬¬¬¬­¬­¬­¬­¬¬¬¬¬­­­­¬¬­­¬¬¬­­­­®®­¬¬®®®®®®®¿11111®®¿1¿11111111111111111111®11¿11111111111111¿1111¿11¿11¿1®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­®®®®­­­­­­¬¬¬¬¬¬­­­¬¬­­¬­¬­­¬­­­­­­­­­®®®®­®®­­­­­­­­­­­­­®­­­­­­­­®®­­­­¬¬¬­­­¬­­­­­¬¬­­¬¬­¬¬­¬­¬­¬¬¬¬­­¬¬­¬¬¬¬­¬­¬¬­¬¬®®®­­­­­­­­­¬¬¬­­­¬­¬­­¬­¬­¬­¬­­­¬­¬¬­­­¬­­¬­­­®­­®®®®®®®®®11111111111®®®¿1111¿®®®®¿11¿¿11111111111111111¿11¿1¿¿¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­­®®®­­­­­­­­¬­¬¬­­­¬¬¬¬¬¬­­¬¬¬¬­­­¬­­­­­®®®®®®­®®­­®­­®­­­­¬­®®­­­­­­­­­­®­­¬­­­¬¬­­­­­­­­¬¬­¬¬¬¬¬­­­¬¬¬¬­¬¬­¬¬­¬­­®®®®®®®­­®­­­­¬­¬­­¬­¬¬­¬¬­¬¬­¬¬¬­¬¬­¬­¬¬­¬­¬¬­¬¬­­­­­­­®­­­¬­®®®¿®®®®®®®®®®®®®1111111111111¿111111111¿1¿¿1¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­®®®®®­­®­­­­­­­®®­­¬­­­­­­¬¬¬­¬­¬­¬¬­­­­­¬¬¬¬­­­­­­­­®®®®®®®®®­®­­­­­­­­­¬­­­®®®­­­­­­­­­­­­­­­­­­¬¬­­­­­¬­­¬­­­­­¬¬­¬¬­¬¬­­¬­­¬­¬¬¬¬­¬­¬­¬­®®®®®®®®®®­­­­¬¬¬­­¬¬­¬¬¬­¬¬­¬¬­¬¬­¬¬­¬¬­¬­­¬­¬¬­¬­­¬¬¬­­­­­­¬¬®®®®®®®®1®®®®®®®®®®®®®­111111111111¿¿11111111¿¿1¿11111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®­­­­®®®­­­­­¬­­­­¬­¬¬­¬¬¬¬¬¬­­­­­­¬¬­­­­­­­­­®­®®®®®®­­­­­­­­­­®­­­­­­­­­­­­­­­­­¬­¬­­­­­­­¬¬¬¬­¬¬­¬­­­­­­­­­¬¬¬¬¬­¬¬­®®®®®®®®®­­­­­­¬¬­­­¬­¬­­­¬­¬­¬¬­¬¬­­¬¬­­¬­¬­¬­­­¬­­¬­­­­­®­­®®®®®®®®®¬¬®®®®®®®®111111111111¿1111111111¿1111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®®®®®®®­­­­­®®®®®®­­­­­¬­¬­¬¬¬¬­¬¬­­¬¬­­­­¬­­­­­®­®­­®®®­­®®®­­­­­­­­­­­­­¬­­­­­­­¬­­­­¬­­¬­­­¬¬­­­­­¬¬­­­¬¬­­­­¬­¬­¬­¬­¬­¬­¬®®®®®®®®­­­­­¬­¬­¬¬­¬¬¬¬­¬¬­¬¬­¬¬­¬¬­­­¬¬¬­¬­­­¬­¬¬­­­¬­­¬­­­­®­­®®­­­­®®®®®®®®®®111111¿11111111111111¿¿¿1¿¿¿11®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­®­­­­­¬­­­­­¬¬­¬¬­¬¬­¬¬­­­­­­­¬®­­­­­®­®®®®®®®­­­­­­­­­­­­­­­­­­­­­­¬­­­­­­­­­®­­­¬¬¬¬­­­¬­¬¬­­­­­­­­­­­­¬­¬¬¬­¬¬®®®®®®®®­­­­­¬¬­­¬­­¬¬¬¬¬¬­¬¬­¬¬¬­¬­¬­¬¬­­­¬­¬­¬­¬¬­¬¬­­­®­­­­¬¬¬¬­­­¬¬¬¬¬1111111111111111111111¿¿1¿¿1¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®®­­­­­­­­®­­­¬¬¬¬¬­¬­­­­¬­­­®­­­­­¬­®­®®®®®®®®­­­¬¬­­­­­®®­­­­­­¬¬¬­­­­¬­­­­­­­­­¬¬­¬­¬¬­¬¬­­­¬­¬¬­­¬¬­­¬¬¬­¬­­¬¬­¬­®®®®®®®®­­­¬­­­¬¬­¬¬¬¬­¬­­­¬¬­¬¬¬¬­¬¬¬¬­¬¬­¬­­­­¬¬­¬­­­®­­¬¬­¬¬¬¬­­¬¬­¬¬¬¬¬¬¬¬­­®®111111111111111111111¿¿1¿¿1111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®­­­­­®­­­­­­­­­¬¬¬­­¬­­­­­­­­­­¬¬¬­¬®­®®®®®®®®®®®®­­­­­­­­­­­®­­­­­­­­¬­¬­­¬­­­¬­­­­¬­¬­¬¬­­¬­­­¬­­­­­­­¬­¬¬­¬¬­¬¬¬¬­¬¬­¬®®®®®­­­¬¬¬­¬¬¬­­¬¬­¬¬¬¬¬­¬¬­¬¬¬¬­¬­¬­¬­­­­¬­­­­­¬­­®­­¬­¬¬¬¬­¬¬¬¬­¬¬¬¬¬­¬¬¬­®­11¿¿11111111111111111¿111¿¿111®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­­­®®­­­­­­­¬­­­¬¬¬¬­­­­­­­­­­­­­®®®®®®®®®®®®®®®®®­­¬­­¬­­­®­­­­­­­­­­¬­­­­­­­¬­¬­­­­­­­­­­­­­­­­­­­­­­­¬¬¬¬­¬­­¬­¬¬®®®®®­­­­­¬¬­¬¬­¬¬¬­¬¬¬¬­¬¬¬­¬­­­­­­­¬¬­­¬­¬­¬­¬¬­¬¬¬­¬¬­¬¬­¬­¬¬¬¬­¬¬¬¬­­¬¬­­­­®1¿¿1111111111111¿¿111¿11¿11¿1¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®­­­­­­­¬­­¬¬¬­¬­­­­­­®­­­­®®®®®®®®®®®®®®®®®®­¬¬¬­¬¬­­¬­­­­­­­¬¬­¬­¬­­­¬¬­¬¬­¬¬­¬­­­¬­­¬­­­­­¬­­¬­­­¬¬­­­¬¬¬¬¬¬¬¬¬­¬¬­­­­®®®®®­­­­­¬¬­¬­¬­¬¬­¬¬­¬¬­¬­¬¬¬­­¬­¬¬­¬­¬­­­¬­¬¬­¬­¬¬­®­®®­­¬¬¬¬¬¬¬­¬¬¬¬¬¬­¬­¬­­®1¿11111111111111¿1¿¿¿1¿11¿¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­®®®®­­­®®­­®­­­­­­­­­­¬­¬¬­¬¬­¬¬¬­­­­­­­­­®®®®®®®®®®®®®®®®­¬­­¬­­®­¬¬­­®®®­­­­­­­­­¬­­­­¬¬¬¬¬¬­¬­¬­¬­­­­¬­¬­­­¬­¬¬­­¬¬¬¬¬¬­¬¬­¬¬­¬¬­¬­­®®®®®®­®­­­¬¬­¬­­¬¬­¬¬­¬¬­¬­¬¬¬¬¬­¬­­¬­­¬¬­¬­¬¬¬¬­­¬¬¬­¬­¬­¬¬¬¬¬¬¬¬¬­­­­­¬¬­¬¬¬­­¿1111111111111111¿¿¿¿1¿¿111¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­®­­­­­­­­­­­¬¬­­­­­¬¬®­­­­­­­®®®®®®®®®®®®®®®®®­­­­¬­­­­®®­­­­­®­­­­¬¬­¬­¬¬¬¬­­­­­­­­­­­¬¬­­­­­­¬¬­¬¬¬¬¬­¬­¬¬¬¬¬¬­¬¬­¬­®®®­­­­¬­¬­¬¬­¬­­¬¬¬¬­¬¬­¬¬­¬­¬¬¬­¬­­¬­¬­­¬¬¬­­­®¬­¬­­¬­¬¬­¬¬¬¬¬¬¬­¬¬­¬­­­®11111111111111111111111111111111111¿1¿¿1¿¿11¿1¿¿¿¿¿¿¿¿¿¿¿11¿¿¿1¿¿¿¿¿¿®®®®®®®®®®®®®®®®®®®®®®®®¿®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®{ "worldtype" "2" "sounds" "6" "classname" "worldspawn" "wad" "gfx/base.wad" "message" "the Slipgate Complex" } { "classname" "info_player_start" "origin" "480 -352 88" "angle" "90" } { "classname" "light" "origin" "480 96 168" "light" "250" } { "classname" "light" "origin" "480 288 168" "light" "250" } { "classname" "light" "origin" "272 96 80" } { "origin" "272 288 80" "classname" "light" } { "classname" "light" "origin" "272 192 80" } { "origin" "688 192 80" "classname" "light_fluorospark" "style" "10" } { "style" "10" "classname" "light" "origin" "688 288 80" } { "origin" "688 96 80" "classname" "light" "style" "10" } { "classname" "light" "origin" "480 -280 168" "light" "200" } { "origin" "480 -144 168" "classname" "light" "light" "200" } { "classname" "light" "origin" "480 -376 120" "light" "200" } { "light" "160" "origin" "480 -40 168" "classname" "light" } { "speed" "400" "sounds" "2" "angle" "270" "classname" "func_door" "model" "*1" } { "speed" "400" "angle" "90" "classname" "func_door" "model" "*2" } { "light" "250" "origin" "592 544 88" "classname" "light_fluoro" } { "origin" "456 600 104" "classname" "light" } { "light" "180" "origin" "688 648 136" "classname" "light" } { "classname" "light" "origin" "688 520 136" "light" "180" } { "origin" "688 480 80" "classname" "item_armor1" } { "angle" "180" "spawnflags" "768" "origin" "616 72 40" "classname" "monster_army" } { "light" "250" "origin" "0 576 120" "classname" "light" } { "light" "180" "origin" "160 576 72" "classname" "light" } { "light" "200" "origin" "560 -32 72" "classname" "light" } { "light" "200" "classname" "light" "origin" "400 -32 72" } { "light" "200" "origin" "0 712 72" "classname" "light" } { "classname" "light" "origin" "0 728 -136" "light" "200" } { "light" "200" "origin" "0 592 -136" "classname" "light" } { "wait" "5" "angle" "-2" "sounds" "2" "targetname" "t1" "classname" "func_door" "dmg" "10" "model" "*3" } { "sounds" "1" "target" "t1" "angle" "180" "classname" "func_button" "model" "*4" } { "light" "200" "origin" "412 780 136" "classname" "light" } { "light" "200" "classname" "light" "origin" "328 904 72" } { "light" "200" "origin" "168 800 72" "classname" "light" } { "light" "200" "classname" "light" "origin" "-72 864 72" } { "origin" "264 888 -136" "classname" "light" } { "classname" "light" "origin" "-8 992 -136" "light" "200" } { "light" "250" "classname" "light" "origin" "272 1064 -136" } { "light" "250" "origin" "-8 1232 -136" "classname" "light" } { "light" "250" "classname" "light" "origin" "256 1272 -136" } { "light" "250" "origin" "312 1464 -136" "classname" "light" } { "light" "200" "origin" "128 968 72" "classname" "light" } { "light" "250" "classname" "light" "origin" "-48 1168 72" } { "light" "250" "origin" "312 1168 72" "classname" "light" } { "light" "220" "classname" "light" "origin" "128 1504 -120" } { "light" "250" "classname" "light" "origin" "-56 1464 -136" } { "sounds" "2" "classname" "func_door" "angle" "180" "speed" "400" "model" "*5" } { "classname" "func_door" "angle" "0" "speed" "400" "model" "*6" } { "classname" "light_fluoro" "origin" "176 1744 -152" } { "origin" "80 1744 -152" "classname" "light_fluoro" } { "light" "250" "origin" "-232 1600 -136" "classname" "light" } { "light" "250" "classname" "light" "origin" "488 1600 -136" } { "origin" "-56 1448 72" "classname" "light" "light" "250" } { "light" "250" "classname" "light" "origin" "312 1448 72" } { "light" "260" "classname" "light_fluoro" "origin" "416 2064 -112" } { "light" "260" "origin" "416 1968 -112" "classname" "light_fluoro" } { "light" "250" "origin" "128 1880 -112" "classname" "light" } { "origin" "616 1944 -88" "classname" "light" } { "style" "10" "classname" "light_fluorospark" "origin" "344 2216 -88" } { "light" "180" "origin" "352 2016 -112" "classname" "light" } { "classname" "light" "origin" "128 2056 -112" "light" "250" } { "light" "250" "origin" "-112 1984 -112" "classname" "light" } { "light" "350" "origin" "-472 2064 -88" "classname" "light_fluoro" } { "classname" "light" "origin" "-192 2208 8" "light" "250" } { "light" "250" "origin" "-424 2208 8" "classname" "light" } { "light" "250" "origin" "-248 2088 -96" "classname" "light" } { "origin" "-200 2384 -72" "classname" "light" } { "classname" "light" "origin" "-424 2384 -72" } { "light" "200" "origin" "-448 2408 -128" "classname" "light" } { "classname" "light" "origin" "-176 2408 -128" "light" "200" } { "sounds" "1" "classname" "func_plat" "model" "*7" } { "light" "350" "origin" "-352 2656 184" "classname" "light" } { "light" "350" "classname" "light" "origin" "-352 2464 184" } { "origin" "-576 2800 -40" "classname" "light" } { "light" "500" "origin" "160 2920 232" "classname" "light" } { "classname" "light" "origin" "160 2720 232" "light" "500" } { "origin" "-288 2992 8" "classname" "light" } { "classname" "light" "origin" "-168 2776 -40" } { "classname" "light" "origin" "160 2824 104" "light" "200" } { "light" "150" "origin" "-64 2760 136" "classname" "light" } { "light" "200" "origin" "16 2832 -152" "classname" "light" } { "classname" "light" "origin" "304 2832 -152" "light" "200" } { "origin" "504 2816 16" "classname" "light" } { "sounds" "3" "wait" "-1" "speed" "600" "targetname" "t2" "spawnflags" "1" "angle" "270" "classname" "func_door" "model" "*8" } { "classname" "light" "origin" "160 2840 -152" "light" "200" } { "light" "80" "origin" "16 2904 -88" "classname" "light" } { "classname" "light" "origin" "304 2904 -88" "light" "80" } { "classname" "light" "origin" "160 2904 -88" "light" "80" } { "wait" "-1" "sounds" "1" "target" "t2" "speed" "50" "angle" "270" "classname" "func_button" "model" "*9" } { "light" "100" "origin" "0 1800 -32" "classname" "light" } { "classname" "light" "origin" "248 1800 -32" "light" "100" } { "style" "32" "targetname" "t3" "origin" "8 2352 200" "classname" "light" } { "style" "32" "targetname" "t3" "classname" "light" "origin" "32 2392 200" } { "style" "32" "targetname" "t3" "origin" "56 2352 200" "classname" "light" } { "style" "32" "targetname" "t3" "classname" "light" "origin" "32 2312 200" } { "style" "32" "targetname" "t3" "light" "200" "origin" "32 2352 88" "classname" "light" } { "spawnflags" "2048" "origin" "112 2352 16" "classname" "weapon_nailgun" } { "sounds" "3" "targetname" "t3" "spawnflags" "3" "angle" "270" "classname" "func_door_secret" "model" "*10" } { "style" "32" "sounds" "3" "target" "t3" "classname" "trigger_once" "model" "*11" } { "origin" "304 2368 96" "classname" "light" } { "angle" "180" "origin" "248 2392 40" "classname" "monster_army" } { "origin" "272 2352 64" "classname" "item_spikes" } { "style" "32" "sounds" "3" "target" "t3" "classname" "trigger_once" "model" "*12" } { "origin" "832 2608 16" "classname" "light" "light" "220" } { "light" "220" "classname" "light" "origin" "832 2480 0" } { "light" "240" "origin" "800 2816 24" "classname" "light" } { "style" "33" "targetname" "t11" "spawnflags" "1" "classname" "light" "origin" "752 2000 -88" "light" "400" } { "style" "34" "spawnflags" "1" "targetname" "t12" "origin" "1280 2000 -152" "classname" "light" "light" "400" } { "style" "35" "spawnflags" "1" "targetname" "t13" "classname" "light" "origin" "1280 2496 -216" "light" "400" } { "style" "36" "spawnflags" "1" "targetname" "t14" "origin" "784 2496 -280" "classname" "light" } { "classname" "light" "origin" "1368 2584 -488" "light" "200" } { "origin" "1368 1944 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "696 2584 -488" "light" "150" } { "origin" "1016 2584 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "1016 1944 -488" "light" "200" } { "origin" "1368 2272 -488" "classname" "light" "light" "200" } { "classname" "light" "origin" "696 2272 -488" "light" "200" } { "classname" "light" "origin" "960 2296 -488" "light" "200" } { "light" "200" "origin" "1032 2352 -488" "classname" "light" } { "classname" "light" "origin" "888 2352 -488" "light" "200" } { "light" "200" "origin" "960 2408 -488" "classname" "light" } { "light" "100" "classname" "light" "origin" "984 2448 -304" } { "classname" "light" "origin" "832 2360 112" "light" "400" } { "classname" "light" "origin" "1144 2448 -488" } { "origin" "1232 2360 -488" "classname" "light" } { "classname" "light" "origin" "1320 2448 -488" "light" "200" } { "light" "200" "origin" "1232 2536 -488" "classname" "light" } { "classname" "light" "origin" "1232 2136 -488" } { "origin" "1144 2048 -488" "classname" "light" } { "classname" "light" "origin" "1232 1960 -488" "light" "200" } { "light" "200" "origin" "1320 2048 -488" "classname" "light" } { "classname" "light" "origin" "832 2336 -200" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "sounds" "3" "model" "*13" } { "classname" "func_door_secret" "angle" "180" "sounds" "3" "model" "*14" } { "classname" "light" "origin" "552 2480 -56" "light" "200" } { "light" "200" "origin" "544 2296 -56" "classname" "light" } { "classname" "light" "origin" "664 2480 -56" "light" "200" } { "classname" "func_door" "targetname" "t4" "angle" "-2" "spawnflags" "1" "sounds" "2" "model" "*15" "lip" "7" // svdijk -- added to prevent z-fighting } { "classname" "trigger_multiple" "target" "t4" "health" "1" "model" "*16" } { "spawnflags" "2048" "classname" "func_door" "angle" "90" "targetname" "t5" "wait" "-1" "sounds" "2" "model" "*17" } { "spawnflags" "2048" "classname" "trigger_once" "target" "t5" "model" "*18" } { "classname" "item_artifact_super_damage" "origin" "544 2480 -88" } { "classname" "light" "origin" "832 2104 -208" } { "classname" "light" "origin" "832 2048 -368" "light" "150" } { "classname" "light" "origin" "1120 2464 112" } { "origin" "1120 2080 112" "classname" "light" } { "classname" "light" "origin" "752 2080 112" "light" "200" } { "classname" "light" "origin" "1048 2280 -72" } { "classname" "func_button" "angle" "270" "target" "t1" "model" "*19" } { "classname" "light" "origin" "1136 1848 -504" "light" "220" } { "origin" "1136 1672 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1008 1672 -504" "light" "220" } { "origin" "1008 1848 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1288 1848 -504" "light" "220" } { "origin" "1400 1584 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1224 1584 -504" "light" "220" } { "origin" "1400 1736 -504" "classname" "light" "light" "220" } { "origin" "880 1672 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "744 1672 -504" "light" "220" } { "classname" "light" "origin" "1312 1648 -392" "light" "220" } { "light" "170" "origin" "1312 1520 -392" "classname" "light" } { "classname" "light" "origin" "1200 1760 -392" "light" "220" } { "light" "170" "origin" "1072 1760 -392" "classname" "light" } { "classname" "light" "origin" "944 1760 -392" "light" "170" } { "origin" "832 1992 -208" "classname" "light" "light" "220" } { "origin" "744 1832 -504" "classname" "light" } { "light" "170" "origin" "832 1760 -392" "classname" "light" } { "light" "220" "origin" "680 1936 -504" "classname" "light" } { "classname" "light" "origin" "1312 1392 -352" "light" "170" } { "light" "170" "origin" "1312 1264 -288" "classname" "light" } { "classname" "light" "origin" "1312 1136 -232" } { "origin" "1224 1456 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1400 1456 -504" "light" "220" } { "origin" "1400 1328 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1224 1328 -504" "light" "220" } { "origin" "1224 1200 -504" "classname" "light" "light" "220" } { "classname" "light" "origin" "1400 1200 -504" "light" "220" } { "origin" "1312 960 -208" "classname" "light" } { "classname" "trigger_teleport" "target" "t6" "model" "*20" } { "classname" "light" "origin" "1312 912 -472" } { "classname" "light" "origin" "1312 1080 -368" } { "classname" "light" "origin" "1128 1064 -504" "light" "170" } { "origin" "1128 856 -504" "classname" "light" "light" "170" } { "classname" "light" "origin" "1496 856 -504" "light" "170" } { "origin" "1496 1064 -504" "classname" "light" "light" "170" } { "classname" "light" "origin" "1312 776 -504" "light" "170" } { "spawnflags" "2" "angle" "90" "classname" "func_door_secret" "model" "*21" } { "origin" "1072 1024 -168" "classname" "light" } { "spawnflags" "1" "height" "400" "angle" "-1" "sounds" "1" "classname" "func_plat" "model" "*22" } { "targetname" "t8" "spawnflags" "2" "angle" "90" "classname" "func_door_secret" "model" "*23" } { "target" "t8" "classname" "trigger_multiple" "model" "*24" } { "light" "220" "origin" "792 888 -248" "classname" "light" } { "light" "180" "classname" "light" "origin" "944 608 -248" } { "light" "150" "origin" "792 512 -248" "classname" "light" } { "classname" "light" "origin" "792 512 -56" "light" "150" } { "classname" "light" "origin" "624 928 -240" "light" "220" } { "light" "220" "origin" "504 1200 -248" "classname" "light" } { "origin" "936 800 -248" "classname" "light" "light" "180" } { "light" "180" "classname" "light" "origin" "960 984 -208" } { "classname" "light" "origin" "792 512 128" "light" "150" } { "spawnflags" "2" "origin" "944 1008 -272" "classname" "item_health" } { "spawnflags" "1792" "origin" "144 2352 16" "classname" "weapon_rocketlauncher" } { "spawnflags" "1792" "origin" "1216 1040 -432" "classname" "weapon_grenadelauncher" } { "spawnflags" "1793" "origin" "1392 1024 -432" "classname" "item_rockets" } { "targetname" "t6" "origin" "-32 1800 -56" "classname" "info_teleport_destination" } { "spawnflags" "1792" "origin" "832 2448 -368" "classname" "weapon_supernailgun" } { "spawnflags" "1792" "origin" "128 1216 -208" "classname" "weapon_supershotgun" } { "origin" "296 2136 -192" "classname" "item_shells" } { "spawnflags" "1" "origin" "1424 904 -432" "classname" "item_health" } { "classname" "item_health" "origin" "1376 808 -432" } { "origin" "1176 936 -432" "classname" "item_health" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*25" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*26" } { "spawnflags" "2048" "target" "t9" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*27" } { "target" "t10" "targetname" "t9" "count" "3" "classname" "trigger_counter" "model" "*28" } { "message" "You must press the three buttons..." "spawnflags" "2048" "sounds" "2" "wait" "-1" "targetname" "t10" "angle" "180" "classname" "func_door" "model" "*29" } { "light" "150" "origin" "832 1928 -384" "classname" "light" } { "style" "33" "sounds" "3" "target" "t11" "classname" "trigger_once" "model" "*30" } { "style" "34" "sounds" "3" "target" "t12" "classname" "trigger_once" "model" "*31" } { "style" "35" "sounds" "3" "target" "t13" "classname" "trigger_once" "model" "*32" } { "style" "36" "sounds" "3" "target" "t14" "classname" "trigger_once" "model" "*33" } { "sounds" "1" "wait" "-1" "targetname" "t11" "spawnflags" "1" "angle" "-2" "classname" "func_door" "model" "*34" } { "targetname" "t12" "classname" "func_door" "angle" "-2" "spawnflags" "1" "wait" "-1" "sounds" "1" "model" "*35" } { "targetname" "t13" "sounds" "1" "wait" "-1" "spawnflags" "1" "angle" "-2" "classname" "func_door" "model" "*36" } { "targetname" "t14" "classname" "func_door" "angle" "-2" "spawnflags" "1" "wait" "-1" "sounds" "1" "model" "*37" } { "angle" "90" "origin" "1312 880 -248" "classname" "info_player_deathmatch" } { "spawnflags" "1" "origin" "1376 1024 -272" "classname" "item_spikes" } { "origin" "1184 992 -272" "classname" "item_health" } { "spawnflags" "1" "origin" "1376 856 -272" "classname" "item_health" } { "spawnflags" "1" "origin" "1256 1704 -432" "classname" "item_health" } { "angle" "90" "origin" "480 48 24" "classname" "info_player_deathmatch" } { "angle" "180" "origin" "528 1888 -168" "classname" "info_player_deathmatch" } { "angle" "0" "origin" "-272 2928 -56" "classname" "info_player_deathmatch" } { "angle" "0" "origin" "832 2048 -152" "classname" "info_player_deathmatch" } { "speed" "300" "message" "This door opens elsewhere..." "spawnflags" "2048" "targetname" "t15" "angle" "270" "classname" "func_door" "wait" "-1" "model" "*38" } { "spawnflags" "2048" "target" "t15" "classname" "trigger_once" "model" "*39" } { "spawnflags" "1792" "origin" "480 576 0" "classname" "weapon_nailgun" } { "spawnflags" "1793" "origin" "464 728 64" "classname" "item_spikes" } { "origin" "328 848 -224" "classname" "item_health" } { "classname" "item_health" "origin" "344 920 -224" } { "spawnflags" "1" "origin" "-16 2064 -208" "classname" "item_health" } { "spawnflags" "1792" "origin" "-480 2240 -160" "classname" "item_rockets" } { "spawnflags" "1793" "origin" "-96 2456 16" "classname" "item_shells" } { "classname" "item_rockets" "origin" "-104 2216 16" "spawnflags" "1793" } { "classname" "item_artifact_invulnerability" "origin" "256 1808 -40" "spawnflags" "1792" } { "classname" "monster_army" "origin" "0 576 24" "angle" "0" "spawnflags" "256" } { "classname" "monster_army" "origin" "8 1520 -200" "angle" "270" } { "classname" "monster_dog" "origin" "88 1520 -200" "angle" "270" } { "classname" "monster_army" "origin" "224 1552 -200" "angle" "270" "spawnflags" "768" } { "spawnflags" "768" "angle" "270" "origin" "-8 936 -200" "classname" "monster_army" } { "classname" "monster_army" "origin" "648 736 104" "spawnflags" "768" "angle" "180" } { "classname" "item_artifact_envirosuit" "origin" "712 2040 -408" "angle" "90" } { "classname" "light" "origin" "712 2040 -360" "light" "100" } { "classname" "item_rockets" "origin" "1328 2536 -528" "spawnflags" "1793" } { "classname" "item_health" "origin" "916 2416 -136" "spawnflags" "2" } { "spawnflags" "1" "classname" "monster_army" "origin" "1312 936 -248" "angle" "90" } { "classname" "monster_dog" "origin" "1336 1784 -408" "angle" "180" "spawnflags" "257" } { "spawnflags" "257" "angle" "90" "origin" "1392 928 -248" "classname" "monster_army" } { "classname" "monster_army" "origin" "1384 1008 -248" "angle" "90" "spawnflags" "768" } { "spawnflags" "768" "angle" "90" "origin" "1240 1008 -248" "classname" "monster_army" } { "classname" "monster_army" "origin" "1256 1760 -408" "angle" "180" "spawnflags" "257" } { "classname" "monster_army" "origin" "824 1784 -408" "spawnflags" "257" "angle" "90" } { "classname" "monster_dog" "origin" "1128 1760 -408" "angle" "180" "spawnflags" "769" } { "classname" "path_corner" "origin" "880 2048 -168" "target" "t16" "targetname" "t17" } { "origin" "1232 2048 -232" "classname" "path_corner" "targetname" "t16" "target" "t17" } { "classname" "monster_army" "origin" "1232 2088 -216" "target" "t16" } { "classname" "monster_army" "origin" "1232 2448 -280" "angle" "270" "spawnflags" "256" } { "classname" "monster_army" "origin" "832 2464 -344" "angle" "0" "spawnflags" "256" } { "classname" "monster_army" "origin" "832 2072 -408" "angle" "90" } { "classname" "monster_dog" "origin" "840 1960 -408" "angle" "90" "spawnflags" "768" } { "classname" "trigger_multiple" "target" "t18" "health" "1" "model" "*40" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "targetname" "t18" "model" "*41" } { "classname" "weapon_supershotgun" "origin" "-360 2912 -80" } { "classname" "trigger_multiple" "target" "t18" "model" "*42" } { "classname" "light" "origin" "-352 2912 -24" "light" "120" } { "classname" "light" "origin" "160 3024 0" "light" "120" } { "classname" "item_shells" "origin" "528 720 80" } { "classname" "monster_army" "origin" "416 1912 -168" "angle" "180" "spawnflags" "768" } { "classname" "monster_dog" "origin" "432 2120 -168" "angle" "180" "spawnflags" "256" } { "classname" "path_corner" "origin" "248 1992 -200" "targetname" "t19" "target" "t20" } { "origin" "-200 1992 -200" "classname" "path_corner" "targetname" "t20" "target" "t21" } { "classname" "path_corner" "origin" "-136 1912 -200" "targetname" "t21" "target" "t22" } { "origin" "248 1912 -200" "classname" "path_corner" "target" "t19" "targetname" "t22" } { "classname" "monster_army" "origin" "80 2024 -184" "target" "t20" } { "classname" "monster_army" "origin" "-16 1888 -184" "spawnflags" "256" "target" "t22" } { "classname" "monster_dog" "origin" "-248 2144 -136" "spawnflags" "768" "angle" "315" } { "classname" "path_corner" "origin" "-560 2352 40" "targetname" "t23" "target" "t24" } { "origin" "-104 2352 40" "classname" "path_corner" "target" "t23" "targetname" "t24" } { "classname" "monster_army" "origin" "-432 2352 56" "spawnflags" "768" "target" "t23" } { "angle" "0" "classname" "monster_dog" "origin" "-544 2584 56" "spawnflags" "256" } { "classname" "monster_army" "origin" "-344 2656 -104" "angle" "270" } { "classname" "monster_dog" "origin" "-72 2896 -56" "spawnflags" "256" "angle" "225" } { "classname" "monster_army" "origin" "432 2920 -56" "target" "t25" } { "classname" "monster_army" "origin" "424 2832 -56" "spawnflags" "256" "angle" "180" } { "classname" "path_corner" "origin" "368 2936 -72" "targetname" "t25" "target" "t26" } { "origin" "368 2696 -72" "classname" "path_corner" "targetname" "t26" "target" "t27" } { "classname" "path_corner" "origin" "480 2696 -72" "targetname" "t27" "target" "t28" } { "origin" "480 2936 -72" "classname" "path_corner" "target" "t25" "targetname" "t28" } { "classname" "monster_army" "origin" "424 2672 -56" "target" "t27" } { "classname" "monster_army" "origin" "424 2880 -56" "angle" "180" "spawnflags" "768" } { "classname" "monster_army" "origin" "424 2760 -56" "spawnflags" "768" "angle" "180" } { "classname" "path_corner" "origin" "832 2712 -88" "targetname" "t29" "target" "t30" } { "origin" "832 2416 -104" "classname" "path_corner" "target" "t29" "targetname" "t30" } { "classname" "monster_army" "origin" "848 2584 -72" "spawnflags" "257" "target" "t29" } { "classname" "monster_army" "origin" "824 2008 -152" "angle" "90" "spawnflags" "768" } { "classname" "item_health" "origin" "-376 1704 -224" "spawnflags" "1" } { "angle" "180" "spawnflags" "768" "origin" "248 2352 40" "classname" "monster_army" } { "spawnflags" "768" "angle" "270" "origin" "-72 2464 40" "classname" "monster_army" } { "spawnflags" "768" "angle" "225" "origin" "904 1024 -248" "classname" "monster_army" } { "light" "100" "style" "10" "classname" "light" "origin" "688 0 80" } { "message" "Shoot this secret door..." "spawnflags" "1" "angle" "0" "classname" "func_door_secret" "model" "*43" } { "origin" "672 -40 48" "classname" "item_shells" } { "classname" "trigger_secret" "model" "*44" } { "classname" "trigger_secret" "model" "*45" } { "classname" "trigger_secret" "model" "*46" } { "classname" "trigger_secret" "model" "*47" } { "classname" "trigger_secret" "model" "*48" } { "classname" "trigger_secret" "model" "*49" } { "light" "100" "origin" "0 632 -88" "classname" "light" } { "classname" "item_health" "origin" "600 2200 -128" "spawnflags" "1" } { "light" "220" "classname" "light" "origin" "832 1880 -504" } { "origin" "72 2056 -208" "classname" "misc_explobox" } { "light" "200" "origin" "-128 584 72" "classname" "light" } { "light" "200" "origin" "-128 568 -136" "classname" "light" } { "light" "100" "origin" "-56 632 -168" "classname" "light" } { "light" "200" "origin" "-56 864 -136" "classname" "light" } { "light" "200" "origin" "40 1672 -40" "classname" "light" } { "classname" "light" "origin" "216 1672 -40" "light" "200" } { "classname" "light" "origin" "128 1080 -152" "light" "200" } { "light" "200" "origin" "128 1096 72" "classname" "light" } { "light" "250" "classname" "light" "origin" "-352 1656 72" } { "origin" "608 1640 72" "classname" "light" "light" "250" } { "origin" "-48 1144 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "-48 1256 -320" } { "origin" "320 1256 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "312 1128 -320" } { "origin" "136 1128 -320" "classname" "light" "light" "170" } { "light" "170" "classname" "light" "origin" "136 1272 -320" } { "spawnflags" "3072" "wait" "5" "sounds" "2" "message" "You can jump across..." "classname" "trigger_multiple" "targetname" "t32" "model" "*50" } { "spawnflags" "3072" "wait" "5" "message" "You can jump up here..." "sounds" "2" "classname" "trigger_multiple" "targetname" "t31" "model" "*51" } { "light" "150" "origin" "1008 2128 -408" "classname" "light" } { "light" "250" "origin" "1312 544 -184" "classname" "light" } { "light" "200" "classname" "light" "origin" "1208 456 -184" } { "origin" "1416 456 -184" "classname" "light" "light" "200" } { "light" "170" "origin" "1312 728 -56" "classname" "light" } { "map" "e1m2" "classname" "trigger_changelevel" "model" "*52" } { "classname" "item_health" "origin" "1224 2464 -304" "spawnflags" "1" } { "classname" "light" "origin" "688 1680 -160" "light" "160" } { "light" "160" "origin" "-392 1688 -160" "classname" "light" } { "spawnflags" "768" "angle" "270" "origin" "288 1536 -200" "classname" "monster_army" } { "spawnflags" "768" "origin" "968 2432 -112" "classname" "monster_army" } { "wait" "5" "message" "Walk into the slipgate to exit." "classname" "trigger_multiple" "sounds" "2" "angle" "270" "model" "*53" } { "classname" "trigger_once" "killtarget" "t31" "target" "t31" "spawnflags" "3072" "model" "*54" } { "classname" "trigger_once" "spawnflags" "3072" "target" "t32" "killtarget" "t32" "model" "*55" } { "classname" "item_armor2" "origin" "1312 1048 -432" } { "classname" "ambient_comp_hum" "origin" "250 194 72" } { "origin" "714 194 72" "classname" "ambient_comp_hum" } { "classname" "ambient_comp_hum" "origin" "626 2058 -104" } { "origin" "466 2226 -104" "classname" "ambient_comp_hum" } { "classname" "info_intermission" "origin" "-112 704 56" "mangle" "20 45 0" } { "classname" "info_intermission" "origin" "-208 2736 192" "mangle" "20 225 0" } { "classname" "info_intermission" "origin" "240 2664 104" "mangle" "20 120 0" } { "classname" "info_intermission" "origin" "1376 1936 64" "mangle" "20 135 0" } { "angle" "90" "origin" "528 -296 72" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "432 -296 72" "angle" "90" } { "angle" "90" "origin" "480 -240 72" "classname" "info_player_coop" } { "classname" "func_wall" "spawnflags" "1792" "model" "*56" } { "classname" "func_wall" "spawnflags" "1792" "model" "*57" } { "classname" "ambient_drone" "origin" "1314 450 -200" } { "message" "Castle of the Damned" "wad" "gfx/wizard.wad" "classname" "worldspawn" "worldtype" "0" "sounds" "8" } { "angle" "270" "origin" "1496 1664 296" "classname" "info_player_start" } { "origin" "1432 672 336" "classname" "light" "light" "250" } { "light" "200" "origin" "1496 888 272" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "932 640 340" } { "classname" "light_torch_small_walltorch" "origin" "1104 812 340" } { "classname" "light" "origin" "1104 640 544" "light" "300" } { "light" "175" "origin" "1216 536 353" "classname" "light" } { "light" "250" "origin" "1816 328 448" "classname" "light" } { "light" "200" "origin" "1632 472 208" "classname" "light" } { "light" "200" "origin" "1792 -392 240" "classname" "light" } { "light" "200" "origin" "1452 -124 508" "classname" "light" } { "light" "150" "origin" "1196 -124 508" "classname" "light" } { "light" "150" "origin" "1044 -124 508" "classname" "light" } { "light" "200" "origin" "756 -124 508" "classname" "light" } { "light" "250" "origin" "744 336 145" "classname" "light" } { "light" "200" "origin" "1176 -912 672" "classname" "light" } { "origin" "1328 -544 552" "classname" "light" } { "classname" "light" "origin" "1528 -912 640" "light" "200" } { "light" "200" "classname" "light" "origin" "880 -648 672" } { "origin" "240 -264 392" "classname" "light" "light" "250" } { "classname" "light" "origin" "-352 -504 464" "light" "200" } { "origin" "-448 -608 804" "classname" "light" "light" "450" } { "light" "250" "origin" "776 -912 472" "classname" "light" } { "light" "300" "origin" "1630 -806 428" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "1528 -912 464" "classname" "light" } { "classname" "light" "origin" "1180 -484 560" } { "classname" "light" "origin" "1184 -612 560" } { "classname" "light" "origin" "1016 -368 472" "light" "100" } { "classname" "light" "origin" "1016 -464 472" "light" "100" } { "classname" "light" "origin" "1020 -560 472" "light" "100" } { "classname" "light" "origin" "1208 -776 472" "light" "100" } { "classname" "light" "origin" "1288 -776 472" "light" "100" } { "classname" "light" "origin" "1360 -776 472" "light" "100" } { "light" "200" "origin" "1792 120 376" "classname" "light" } { "origin" "1538 182 356" "classname" "light_torch_small_walltorch" } { "light" "200" "origin" "1640 80 360" "classname" "light" } { "light" "200" "origin" "1928 80 360" "classname" "light" } { "light" "250" "origin" "1792 296 208" "classname" "light" } { "light" "150" "origin" "1800 40 160" "classname" "light" } { "light" "200" "origin" "1776 -392 160" "classname" "light" } { "light" "200" "origin" "1304 -392 152" "classname" "light" } { "light" "250" "origin" "1632 112 136" "classname" "light" } { "light" "250" "origin" "1432 312 136" "classname" "light" } { "light" "200" "origin" "1136 -656 160" "classname" "light" } { "light" "200" "origin" "1136 -416 160" "classname" "light" } { "light" "250" "origin" "1448 -552 160" "classname" "light" } { "light" "200" "origin" "1920 440 136" "classname" "light" } { "light" "200" "origin" "968 88 177" "classname" "light" } { "light" "300" "origin" "1088 312 129" "classname" "light" } { "light" "150" "origin" "1376 168 129" "classname" "light" } { "light" "250" "origin" "112 -384 392" "classname" "light" } { "origin" "300 -1004 508" "classname" "light" } { "origin" "296 -812 505" "classname" "light" } { "origin" "300 -1204 505" "classname" "light" } { "light" "150" "origin" "470 -1006 468" "classname" "light_torch_small_walltorch" } { "light" "250" "origin" "984 -1216 496" "classname" "light" } { "light" "250" "origin" "888 -1128 552" "classname" "light" } { "light" "200" "origin" "800 -1216 592" "classname" "light" } { "light" "200" "origin" "664 -1216 592" "classname" "light" } { "light" "200" "origin" "584 -1136 592" "classname" "light" } { "light" "200" "origin" "584 -968 592" "classname" "light" } { "light" "250" "origin" "584 -744 592" "classname" "light" } { "light" "200" "origin" "528 -1144 464" "classname" "light" } { "light" "200" "origin" "528 -856 464" "classname" "light" } { "light" "200" "classname" "light" "origin" "1496 1544 440" } { "origin" "1384 1392 440" "classname" "light" "light" "250" } { "origin" "1496 1104 520" "classname" "light" } { "origin" "1608 1400 440" "classname" "light" "light" "250" } { "light" "250" "origin" "1240 1712 360" "classname" "light" } { "light" "250" "origin" "1744 1696 360" "classname" "light" } { "classname" "light" "origin" "1384 1136 440" "light" "250" } { "classname" "light" "origin" "1608 1144 440" "light" "250" } { "classname" "path_corner" "origin" "1168 736 296" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "992 744 296" "targetname" "t6" "target" "t7" } { "classname" "path_corner" "origin" "1000 544 296" "targetname" "t7" "target" "t34" } { "classname" "item_health" "origin" "960 704 288" } { "classname" "item_shells" "origin" "952 512 288" } { "classname" "path_corner" "origin" "1344 -128 304" "targetname" "t9" "target" "t8" } { "classname" "path_corner" "origin" "898 -128 304" "targetname" "t8" "target" "t9" } { "spawnflags" "1" "classname" "monster_ogre" "origin" "1018 -126 320" "angle" "0" "target" "t8" } { "classname" "item_health" "origin" "1344 -224 296" "spawnflags" "1" } { "classname" "item_health" "origin" "1400 -224 296" "spawnflags" "1" } { "origin" "1528 192 296" "classname" "item_shells" } { "classname" "path_corner" "origin" "1496 1040 184" "targetname" "t22" "target" "t23" } { "classname" "path_corner" "origin" "1496 840 248" "targetname" "t23" "target" "t33" } { "spawnflags" "1" "classname" "item_shells" "origin" "1056 -648 288" } { "classname" "item_health" "origin" "1184 -736 288" } { "spawnflags" "257" "classname" "monster_army" "origin" "1646 -698 360" "angle" "180" "targetname" "t89" } { "classname" "path_corner" "origin" "1400 640 272" "targetname" "t30" "target" "t79" } { "classname" "path_corner" "origin" "1496 752 232" "targetname" "t33" "target" "t77" } { "classname" "path_corner" "origin" "1192 560 296" "targetname" "t34" "target" "t80" } { "classname" "item_shells" "origin" "1616 1280 176" } { "classname" "item_health" "origin" "1056 -840 416" "spawnflags" "1" } { "classname" "item_health" "origin" "1104 -840 416" "spawnflags" "1" } { "spawnflags" "1" "classname" "monster_army" "origin" "262 -458 320" "angle" "0" "target" "t96" } { "spawnflags" "1024" "classname" "item_health" "origin" "136 -296 296" } { "classname" "path_corner" "origin" "-536 -704 472" "targetname" "t42" "target" "t41" } { "classname" "path_corner" "origin" "-576 -416 472" "targetname" "t41" "target" "t42" } { "classname" "monster_knight" "origin" "-578 -654 480" "target" "t41" "spawnflags" "1" } { "classname" "item_shells" "origin" "-368 -752 456" } { "classname" "item_health" "origin" "-16 -520 360" "spawnflags" "1" } { "classname" "item_health" "origin" "-16 -576 360" "spawnflags" "1" } { "classname" "light" "origin" "1848 -568 320" "light" "200" } { "classname" "light" "origin" "1760 -560 408" "light" "200" } { "classname" "light" "origin" "1624 -560 352" "light" "150" } { "targetname" "t43" "angle" "270" "origin" "800 368 312" "classname" "info_teleport_destination" } { "origin" "752 168 296" "classname" "item_health" } { "target" "t43" "classname" "trigger_teleport" "model" "*1" } { "origin" "1712 -568 256" "classname" "item_health" } { "classname" "monster_ogre" "origin" "1494 1134 208" "angle" "270" "target" "t22" } { "light" "300" "origin" "1856 1288 384" "classname" "light" } { "classname" "light" "origin" "1136 1288 384" } { "light" "200" "origin" "1920 328 380" "classname" "light" } { "target" "t122" "spawnflags" "2048" "sounds" "1" "classname" "item_key1" "origin" "880 -300 464" } { "light" "300" "origin" "648 -384 430" "classname" "light_flame_small_yellow" } { "light" "250" "classname" "light_flame_small_yellow" "origin" "1104 -224 406" } { "light" "250" "origin" "1456 -128 406" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "988 532 353" "light" "175" } { "light" "125" "origin" "1100 648 328" "classname" "light" } { "origin" "1616 936 310" "classname" "light_flame_small_yellow" "light" "300" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "1360 936 310" } { "origin" "1792 504 390" "classname" "light_flame_small_yellow" "light" "300" } { "origin" "1972 -252 332" "classname" "info_null" "targetname" "t47" } { "light" "800" "origin" "1992 -252 336" "classname" "light" "target" "t47" } { "classname" "info_null" "origin" "1948 -292 332" "targetname" "t48" } { "light" "800" "classname" "light" "origin" "1948 -312 336" "target" "t48" } { "origin" "880 -328 562" "classname" "light_flame_small_yellow" "light" "300" } { "classname" "light" "origin" "1056 -1288 504" } { "origin" "1184 -1288 504" "classname" "light" } { "classname" "light" "origin" "1312 -1288 504" } { "origin" "1440 -1288 504" "classname" "light" } { "sounds" "1" "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t50" "model" "*2" } { "sounds" "1" "classname" "func_door" "wait" "-1" "angle" "-2" "targetname" "t50" "model" "*3" } { "classname" "trigger_once" "target" "t50" "model" "*4" } { "classname" "light" "origin" "1368 -1016 504" "light" "200" } { "light" "200" "origin" "1120 -1024 504" "classname" "light" } { "classname" "light" "origin" "1248 -1184 464" "light" "175" } { "classname" "light" "origin" "776 -480 480" "light" "225" } { "classname" "light" "origin" "1904 -144 168" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "1706 -206 316" "light" "300" } { "light" "300" "origin" "2134 -34 316" "classname" "light_torch_small_walltorch" } { "origin" "1152 -296 422" "classname" "light_flame_small_yellow" "light" "250" } { "light" "250" "classname" "light_flame_small_yellow" "origin" "1152 -760 422" } { "origin" "1528 -556 478" "classname" "light_flame_small_yellow" "light" "250" } { "targetname" "t52" "origin" "1532 -552 328" "classname" "info_null" } { "origin" "1340 -544 384" "classname" "item_armor2" } { "sounds" "1" "targetname" "t53" "lip" "64" "wait" "-1" "angle" "-1" "classname" "func_door" "model" "*5" } { "sounds" "1" "targetname" "t53" "classname" "func_door" "angle" "-1" "wait" "-1" "lip" "64" "model" "*6" } { "targetname" "t53" "target" "t54" "classname" "trigger_teleport" "spawnflags" "2" "model" "*7" } { "targetname" "t54" "angle" "180" "origin" "1408 -688 449" "classname" "info_teleport_destination" } { "targetname" "t53" "target" "t57" "classname" "trigger_teleport" "spawnflags" "2" "model" "*8" } { "targetname" "t57" "angle" "180" "origin" "1408 -400 361" "classname" "info_teleport_destination" } { "spawnflags" "768" "targetname" "t53" "angle" "180" "origin" "1912 -856 217" "classname" "monster_wizard" } { "spawnflags" "768" "targetname" "t53" "classname" "monster_wizard" "origin" "1912 -936 217" "angle" "180" } { "targetname" "t50" "angle" "90" "origin" "1320 -1112 441" "classname" "monster_knight" } { "spawnflags" "256" "targetname" "t50" "angle" "0" "origin" "1056 -1144 441" "classname" "monster_knight" } { "sounds" "1" "targetname" "t61" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*9" } { "sounds" "3" "lip" "64" "spawnflags" "1" "targetname" "t58" "angle" "270" "wait" "-1" "classname" "func_door" "model" "*10" } { "sounds" "1" "wait" "-1" "angle" "270" "target" "t58" "classname" "func_button" "model" "*11" } { "target" "t61" "classname" "trigger_once" "model" "*12" } { "light" "225" "origin" "984 -480 480" "classname" "light" } { "light" "175" "origin" "880 -368 176" "classname" "light" } { "classname" "light" "origin" "880 -592 240" "light" "175" } { "light" "200" "origin" "880 -488 184" "classname" "light" } { "light" "150" "origin" "880 -304 472" "classname" "light" } { "classname" "light" "origin" "-96 308 864" "light" "850" } { "origin" "-32 -440 624" "classname" "light" } { "sounds" "1" "targetname" "t73" "wait" "-1" "lip" "196" "angle" "-1" "classname" "func_door" "model" "*13" } { "light" "300" "origin" "104 144 688" "classname" "light" } { "classname" "light" "origin" "-264 144 688" "light" "300" } { "sounds" "1" "targetname" "t73" "wait" "-1" "classname" "func_door" "angle" "-1" "lip" "196" "model" "*14" } { "classname" "light_flame_small_yellow" "origin" "-24 -232 414" "light" "250" } { "lip" "-2" "sounds" "3" "speed" "350" "targetname" "t73" "angle" "180" "wait" "-1" "classname" "func_door" "model" "*15" } { "target" "t63" "targetname" "t62" "origin" "-12 312 264" "classname" "path_corner" } { "target" "t64" "targetname" "t63" "origin" "-12 312 356" "classname" "path_corner" } { "wait" "-1" "target" "t66" "targetname" "t64" "classname" "path_corner" "origin" "-13 440 355" } { "sounds" "1" "targetname" "t71" "wait" "-1" "target" "t65" "angle" "-2" "classname" "func_button" "model" "*16" } { "target" "t64" "targetname" "t66" "origin" "-13 440 355" "classname" "path_corner" } { "light" "200" "origin" "-96 440 376" "classname" "light" } { "light" "150" "origin" "8 456 376" "classname" "light" } { "targetname" "t70" "target" "t67" "classname" "path_corner" "origin" "-220 312 264" } { "target" "t68" "targetname" "t67" "classname" "path_corner" "origin" "-220 312 356" } { "wait" "-1" "target" "t69" "targetname" "t68" "origin" "-221 440 355" "classname" "path_corner" } { "target" "t68" "targetname" "t69" "classname" "path_corner" "origin" "-221 440 355" } { "classname" "light" "origin" "-200 456 376" "light" "150" } { "targetname" "t65" "target" "t62" "classname" "func_train" "speed" "50" "sounds" "1" "model" "*17" } { "light" "250" "origin" "-96 632 406" "classname" "light_flame_small_yellow" } { "targetname" "t72" "origin" "-96 288 304" "classname" "info_null" } { "light" "450" "target" "t72" "origin" "-96 288 368" "classname" "light" } { "target" "t70" "targetname" "t65" "speed" "50" "classname" "func_train" "sounds" "1" "model" "*18" } { "lip" "-2" "sounds" "0" "speed" "350" "classname" "func_door" "wait" "-1" "angle" "0" "model" "*19" } { "targetname" "t65" "delay" "4.7" "target" "t73" "classname" "trigger_once" "model" "*20" } { "targetname" "t73" "angle" "270" "origin" "-96 552 320" "classname" "monster_demon1" "spawnflags" "1024" } { "targetname" "t74" "angle" "90" "origin" "132 -192 476" "classname" "info_teleport_destination" } { "targetname" "t75" "classname" "info_teleport_destination" "origin" "-328 -196 476" "angle" "90" } { "target" "t75" "classname" "trigger_teleport" "spawnflags" "1" "model" "*21" } { "target" "t74" "classname" "trigger_teleport" "spawnflags" "1" "model" "*22" } { "light" "200" "origin" "-418 306 356" "classname" "light" } { "classname" "light" "origin" "260 308 356" "light" "200" } { "sounds" "0" "targetname" "t73" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*23" } { "sounds" "0" "targetname" "t73" "wait" "-1" "angle" "0" "classname" "func_door" "model" "*24" } { "sounds" "0" "wait" "-1" "angle" "0" "targetname" "t73" "classname" "func_door" "model" "*25" } { "sounds" "0" "targetname" "t73" "angle" "180" "wait" "-1" "classname" "func_door" "model" "*26" } { "sounds" "3" "wait" "-1" "angle" "-2" "targetname" "t73" "classname" "func_door" "model" "*27" } { "classname" "light" "origin" "-96 24 360" "light" "100" } { "light" "100" "origin" "-96 -40 360" "classname" "light" } { "classname" "light" "origin" "-160 -568 624" } { "origin" "-160 -440 624" "classname" "light" } { "classname" "light" "origin" "-32 -568 624" } { "classname" "light" "origin" "-96 -88 484" "light" "150" } { "classname" "light" "origin" "-440 -408 804" "light" "450" } { "classname" "light" "origin" "600 -128 352" "light" "200" } { "classname" "light" "origin" "576 -608 504" "light" "250" } { "classname" "light" "origin" "384 -504 392" "light" "250" } { "classname" "light" "origin" "1264 240 295" "light" "250" } { "light" "250" "origin" "944 240 295" "classname" "light" } { "classname" "path_corner" "origin" "1480 704 264" "targetname" "t77" "target" "t78" } { "classname" "path_corner" "origin" "1448 656 264" "targetname" "t78" "target" "t30" } { "classname" "path_corner" "origin" "1264 640 304" "targetname" "t80" "target" "t5" } { "classname" "path_corner" "origin" "1328 640 304" "targetname" "t79" "target" "t80" } { "light" "200" "origin" "1488 -392 216" "classname" "light" } { "classname" "path_corner" "origin" "816 80 304" "targetname" "t83" "target" "t82" "spawnflags" "256" } { "origin" "816 312 304" "classname" "path_corner" "targetname" "t82" "target" "t83" "spawnflags" "256" } { "classname" "monster_army" "origin" "806 206 320" "angle" "90" "target" "t82" "spawnflags" "256" } { "classname" "trigger_once" "target" "t84" "model" "*28" } { "classname" "monster_ogre" "origin" "1790 -146 312" "angle" "90" "targetname" "t84" } { "classname" "path_corner" "origin" "1088 -672 296" "target" "t85" "targetname" "t88" } { "origin" "1088 -376 296" "classname" "path_corner" "targetname" "t85" "target" "t86" } { "classname" "path_corner" "origin" "1088 -376 296" "targetname" "t87" "target" "t88" } { "origin" "1448 -376 296" "classname" "path_corner" "targetname" "t86" "target" "t87" } { "spawnflags" "1" "classname" "monster_ogre" "origin" "1086 -498 312" "angle" "270" "target" "t88" } { "spawnflags" "256" "classname" "trigger_once" "target" "t89" "model" "*29" } { "classname" "item_health" "origin" "352 -752 408" "spawnflags" "1025" } { "spawnflags" "1025" "origin" "352 -792 408" "classname" "item_health" } { "classname" "item_health" "origin" "352 -832 408" "spawnflags" "1" } { "classname" "path_corner" "origin" "408 -776 416" "targetname" "t94" "target" "t95" } { "origin" "400 -1088 416" "classname" "path_corner" "targetname" "t95" "target" "t94" } { "classname" "path_corner" "origin" "584 -1096 416" "targetname" "t92" "target" "t93" } { "origin" "584 -792 416" "classname" "path_corner" "targetname" "t93" "target" "t92" } { "classname" "monster_army" "origin" "390 -970 432" "angle" "0" "target" "t94" } { "classname" "monster_army" "origin" "566 -970 432" "angle" "270" "target" "t92" } { "classname" "path_corner" "origin" "208 -304 304" "targetname" "t97" "target" "t96" } { "classname" "path_corner" "origin" "208 -464 304" "targetname" "t96" "target" "t97" } { "spawnflags" "1280" "classname" "path_corner" "origin" "-344 160 304" "targetname" "t100" "target" "t99" } { "spawnflags" "1280" "origin" "168 152 304" "classname" "path_corner" "targetname" "t99" "target" "t100" } { "spawnflags" "1280" "classname" "monster_ogre" "origin" "240 152 320" "angle" "180" "target" "t99" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "-392 80 320" "angle" "0" "targetname" "t101" } { "spawnflags" "768" "classname" "trigger_once" "target" "t101" "model" "*30" } { "classname" "item_health" "origin" "40 -16 464" } { "origin" "80 -48 464" "classname" "item_health" } { "origin" "520 -72 296" "classname" "item_shells" } { "spawnflags" "1" "origin" "-424 -216 296" "classname" "item_shells" } { "spawnflags" "769" "angle" "270" "origin" "880 -400 568" "classname" "monster_wizard" } { "light" "200" "origin" "432 176 152" "classname" "light" } { "light" "150" "origin" "432 -56 256" "classname" "light" } { "origin" "264 -96 300" "classname" "item_health" } { "classname" "item_health" "origin" "264 -140 300" } { "spawnflags" "1" "origin" "1184 1568 240" "classname" "item_health" } { "classname" "item_health" "origin" "1184 1616 240" "spawnflags" "1" } { "light" "150" "origin" "1496 1112 108" "classname" "light" } { "light" "200" "origin" "1120 1152 96" "classname" "light" } { "light" "200" "origin" "1080 692 184" "classname" "light" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "832 1184 294" } { "origin" "464 536 358" "classname" "light_flame_small_yellow" "light" "300" } { "light" "300" "classname" "light_flame_small_yellow" "origin" "600 704 334" } { "light" "150" "origin" "1736 1096 110" "classname" "light" } { "light" "100" "origin" "832 1056 134" "classname" "light" } { "light" "150" "origin" "784 704 294" "classname" "light" } { "origin" "856 592 182" "classname" "item_health" } { "classname" "item_health" "origin" "824 552 182" } { "classname" "info_player_deathmatch" "origin" "-416 -144 320" "angle" "90" } { "classname" "info_player_deathmatch" "origin" "168 -480 320" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "1496 1328 200" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "1936 -136 312" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "936 -1216 432" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "792 -992 440" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "1080 -720 312" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "408 -752 432" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "792 -208 320" "angle" "45" } { "classname" "info_player_deathmatch" "origin" "784 808 206" "angle" "225" } { "sounds" "3" "wait" "3" "angle" "90" "classname" "func_door" "model" "*31" } { "sounds" "0" "wait" "3" "angle" "270" "classname" "func_door" "model" "*32" } { "spawnflags" "1" "origin" "680 832 182" "classname" "item_shells" } { "origin" "1392 240 300" "classname" "weapon_supershotgun" } { "spawnflags" "769" "angle" "270" "origin" "954 -754 444" "classname" "monster_ogre" } { "spawnflags" "1" "origin" "520 -1280 408" "classname" "item_shells" } { "light" "200" "origin" "-612 -500 548" "classname" "light" } { "classname" "func_door" "angle" "91" // svdijk -- changed to prevent z-fighting (was "90") "targetname" "t110" "wait" "-1" "model" "*33" } { "sounds" "3" "classname" "func_door" "angle" "269" // svdijk -- changed to prevent z-fighting (was "270") "wait" "-1" "model" "*34" } { "classname" "trigger_once" "target" "t110" "model" "*35" } { "classname" "trigger_changelevel" "map" "e1m3" "model" "*36" } { "spawnflags" "1792" "origin" "680 728 184" "classname" "weapon_rocketlauncher" } { "spawnflags" "1792" "origin" "1496 1256 176" "classname" "weapon_nailgun" } { "angle" "180" "spawnflags" "1792" "origin" "-96 -496 360" "classname" "weapon_supernailgun" } { "spawnflags" "1794" "origin" "-112 -8 464" "classname" "item_health" } { "spawnflags" "1793" "origin" "-112 -568 360" "classname" "item_spikes" } { "spawnflags" "1792" "origin" "1616 1424 176" "classname" "item_spikes" } { "spawnflags" "1792" "classname" "item_spikes" "origin" "1656 1424 176" } { "spawnflags" "1792" "origin" "1696 1424 176" "classname" "item_spikes" } { "spawnflags" "768" "target" "t34" "angle" "315" "origin" "1070 646 312" "classname" "monster_ogre" } { "spawnflags" "768" "targetname" "t84" "angle" "90" "origin" "1624 88 376" "classname" "monster_wizard" } { "spawnflags" "768" "angle" "90" "targetname" "t84" "origin" "1866 -378 312" "classname" "monster_ogre" } { "angle" "45" "origin" "1088 -1096 440" "classname" "monster_knight" "targetname" "t50" } { "spawnflags" "768" "classname" "monster_knight" "origin" "1400 -1144 440" "angle" "90" "targetname" "t50" } { "spawnflags" "256" "target" "t111" "targetname" "t112" "origin" "896 -1216 416" "classname" "path_corner" } { "spawnflags" "256" "target" "t112" "targetname" "t111" "classname" "path_corner" "origin" "704 -1216 416" } { "spawnflags" "257" "target" "t111" "angle" "180" "origin" "758 -1218 432" "classname" "monster_army" } { "spawnflags" "768" "target" "t114" "targetname" "t113" "origin" "-96 -520 368" "classname" "path_corner" } { "spawnflags" "768" "target" "t113" "targetname" "t114" "origin" "-96 -152 304" "classname" "path_corner" } { "targetname" "t116" "spawnflags" "769" "target" "t113" "angle" "270" "origin" "-98 -194 320" "classname" "monster_ogre" } { "spawnflags" "1536" "origin" "1936 -96 289" "classname" "item_health" } { "spawnflags" "1025" "origin" "1040 -1200 417" "classname" "item_health" } { "spawnflags" "769" "target" "t117" "angle" "315" "origin" "-560 -312 592" "classname" "monster_wizard" } { "spawnflags" "768" "target" "t118" "targetname" "t117" "origin" "-528 -344 576" "classname" "path_corner" } { "spawnflags" "768" "target" "t117" "targetname" "t118" "origin" "-352 -656 576" "classname" "path_corner" } { "classname" "light" "origin" "1360 976 224" "light" "150" } { "light" "150" "origin" "1616 976 224" "classname" "light" } { "classname" "light" "origin" "1208 1296 368" "light" "250" } { "origin" "1784 1288 368" "classname" "light" "light" "250" } { "classname" "light" "origin" "1496 1664 336" "light" "250" } { "classname" "light" "origin" "1752 1176 112" "light" "150" } { "light" "200" "origin" "1776 976 112" "classname" "light" } { "classname" "light" "origin" "1216 976 112" "light" "200" } { "light" "150" "origin" "1224 1176 112" "classname" "light" } { "classname" "light" "origin" "1496 1432 520" "light" "250" } { "classname" "light" "origin" "1496 1304 264" "light" "200" } { "classname" "light" "origin" "1496 1432 288" "light" "200" } { "classname" "light" "origin" "1608 1120 88" "light" "150" } { "light" "150" "origin" "1384 1120 88" "classname" "light" } { "classname" "light" "origin" "1496 864 368" "light" "150" } { "light" "175" "origin" "980 764 353" "classname" "light" } { "classname" "light" "origin" "1228 764 353" "light" "175" } { "classname" "light" "origin" "1104 464 353" "light" "200" } { "classname" "light" "origin" "1104 -40 423" "light" "200" } { "light" "150" "origin" "1416 -128 367" "classname" "light" } { "classname" "light" "origin" "1104 -184 367" "light" "200" } { "classname" "light" "origin" "1184 56 423" "light" "150" } { "light" "150" "origin" "1024 56 423" "classname" "light" } { "classname" "light" "origin" "1272 -64 399" "light" "150" } { "light" "150" "origin" "888 -64 399" "classname" "light" } { "classname" "light" "origin" "1104 152 129" "light" "300" } { "classname" "light" "origin" "976 392 129" "light" "200" } { "classname" "light" "origin" "1104 656 120" } { "classname" "light" "origin" "896 712 144" "light" "200" } { "classname" "light" "origin" "640 704 280" "light" "200" } { "classname" "light" "origin" "464 496 296" "light" "150" } { "classname" "light" "origin" "888 1152 96" "light" "200" } { "classname" "light" "origin" "840 880 240" "light" "200" } { "classname" "light" "origin" "848 584 240" "light" "150" } { "classname" "light" "origin" "784 160 144" "light" "200" } { "classname" "light" "origin" "440 336 144" "light" "150" } { "light" "150" "origin" "584 336 144" "classname" "light" } { "classname" "light" "origin" "432 24 136" "light" "150" } { "classname" "light" "origin" "656 328 224" "light" "200" } { "classname" "light" "origin" "432 -128 312" "light" "200" } { "classname" "light" "origin" "600 -384 360" "light" "200" } { "origin" "520 -128 406" "classname" "light_flame_small_yellow" "light" "250" } { "classname" "light" "origin" "424 -320 352" "light" "200" } { "classname" "light" "origin" "664 -1216 472" "light" "150" } { "classname" "light" "origin" "336 -1208 504" "light" "150" } { "light" "150" "origin" "336 -1008 504" "classname" "light" } { "classname" "light" "origin" "336 -816 504" "light" "150" } { "classname" "light" "origin" "880 -1000 496" "light" "200" } { "classname" "light" "origin" "880 -792 496" "light" "200" } { "classname" "light" "origin" "880 -376 304" "light" "200" } { "classname" "light" "origin" "1048 -912 480" "light" "225" } { "classname" "light" "origin" "1120 -1192 468" "light" "150" } { "light" "150" "origin" "1376 -1192 468" "classname" "light" } { "classname" "light" "origin" "1472 -912 464" "light" "175" } { "classname" "light" "origin" "880 -304 480" "light" "100" } { "classname" "light" "origin" "880 -680 480" "light" "175" } { "classname" "light" "origin" "1600 -704 484" "light" "150" } { "classname" "light" "origin" "1504 -704 348" "light" "175" } { "light" "175" "origin" "1336 -704 348" "classname" "light" } { "classname" "light" "origin" "1152 -640 332" "light" "200" } { "classname" "light" "origin" "1096 -552 348" "light" "150" } { "light" "200" "origin" "1160 -456 332" "classname" "light" } { "light" "150" "origin" "1216 -384 348" "classname" "light" } { "classname" "light" "origin" "1344 -384 348" "light" "150" } { "classname" "light" "origin" "1544 392 156" "light" "225" } { "light" "225" "origin" "1848 248 156" "classname" "light" } { "classname" "light" "origin" "1936 136 156" "light" "225" } { "light" "200" "origin" "2096 -80 156" "classname" "light" } { "light" "200" "origin" "2048 -408 156" "classname" "light" } { "classname" "light" "origin" "1456 -392 444" "light" "225" } { "classname" "light" "origin" "1640 -384 352" "light" "225" } { "classname" "light_torch_small_walltorch" "origin" "2134 -474 316" "light" "250" } { "light" "200" "origin" "168 216 496" "classname" "light" } { "classname" "light" "origin" "-328 208 496" "light" "200" } { "light" "200" "origin" "-96 360 432" "classname" "light" } { "classname" "light" "origin" "-96 144 432" "light" "200" } { "light" "200" "origin" "-376 32 432" "classname" "light" } { "light" "200" "origin" "208 -72 432" "classname" "light" } { "light" "150" "origin" "-96 72 360" "classname" "light" } { "light" "150" "origin" "-64 -232 368" "classname" "light" } { "light" "150" "origin" "-96 -320 560" "classname" "light" } { "light" "250" "origin" "-96 -496 448" "classname" "light" } { "light" "150" "origin" "-416 -104 392" "classname" "light" } { "light" "150" "origin" "-344 -152 528" "classname" "light" } { "classname" "light" "origin" "160 -152 528" "light" "150" } { "light" "150" "origin" "-96 8 528" "classname" "light" } { "light" "200" "origin" "-560 -504 688" "classname" "light" } { "classname" "light" "origin" "-440 -368 688" "light" "200" } { "light" "200" "origin" "-440 -656 688" "classname" "light" } { "classname" "light" "origin" "-336 -504 688" "light" "200" } { "classname" "light" "origin" "2084 -208 336" "light" "100" } { "light" "100" "origin" "2012 -252 332" "classname" "light" } { "classname" "light" "origin" "1948 -328 332" "light" "100" } { "light" "150" "origin" "1892 -452 332" "classname" "light" } { "sounds" "1" "targetname" "t120" "wait" "-1" "angle" "-2" "classname" "func_door" "lip" "4" "model" "*37" } { "target" "t120" "classname" "trigger_once" "model" "*38" } { "light" "100" "origin" "2076 -312 336" "classname" "light" } { "sounds" "3" "spawnflags" "2064" "angle" "0" "wait" "-1" "classname" "func_door" "model" "*39" } { "spawnflags" "2064" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*40" } { "light" "100" "origin" "332 -264 356" "classname" "light" } { "classname" "light" "origin" "144 -264 356" "light" "100" } { "light" "100" "origin" "1104 572 316" "classname" "light" } { "target" "t121" "wait" ".8" "classname" "trigger_multiple" "model" "*41" } { "targetname" "t121" "angle" "180" "origin" "2120 -256 332" "classname" "trap_spikeshooter" "spawnflags" "1024" } { "targetname" "t121" "angle" "90" "origin" "1944 -456 332" "classname" "trap_spikeshooter" "spawnflags" "1024" } { "light" "150" "origin" "1312 -856 472" "classname" "light" } { "classname" "light" "origin" "1184 -856 472" "light" "175" } { "classname" "light" "origin" "1560 -568 224" "light" "200" } { "classname" "func_door" "angle" "-2" "wait" "-1" "speed" "50" "sounds" "1" "targetname" "t123" "lip" "6" "model" "*42" } { "classname" "trigger_once" "target" "t123" "model" "*43" } { "classname" "light" "origin" "1496 -552 330" "light" "700" "target" "t52" } { "classname" "light" "origin" "1288 80 140" "light" "250" } { "classname" "light" "origin" "1288 400 80" "light" "200" } { "classname" "light" "origin" "1328 -664 160" "light" "200" } { "classname" "item_armor1" "origin" "784 56 304" } { "classname" "light" "origin" "1544 464 352" "light" "75" } { "classname" "func_plat" "model" "*44" } { "classname" "light" "origin" "1496 1192 280" "light" "200" } { "classname" "light" "origin" "1608 1192 136" "light" "100" } { "light" "100" "origin" "1384 1184 136" "classname" "light" } { "light" "100" "origin" "1608 1048 136" "classname" "light" } { "classname" "light" "origin" "1384 1048 136" "light" "100" } { "classname" "light" "origin" "1200 1148 92" "light" "150" } { "light" "150" "origin" "876 -184 367" "classname" "light" } { "classname" "light" "origin" "768 -128 384" "light" "200" } { "classname" "light" "origin" "1104 388 552" "light" "250" } { "light" "200" "origin" "1392 240 384" "classname" "light" } { "classname" "light" "origin" "1392 80 368" "light" "200" } { "classname" "light" "origin" "1272 400 367" "light" "150" } { "light" "150" "origin" "920 400 367" "classname" "light" } { "classname" "light" "origin" "816 208 368" "light" "200" } { "classname" "light" "origin" "800 24 368" "light" "200" } { "classname" "light" "origin" "800 376 385" "light" "150" } { "light" "150" "origin" "1400 400 385" "classname" "light" } { "classname" "path_corner" "origin" "1104 336 300" "target" "t126" "targetname" "t127" } { "origin" "1104 24 300" "classname" "path_corner" "targetname" "t126" "target" "t127" } { "classname" "monster_army" "origin" "1104 424 316" "angle" "270" "target" "t127" } { "targetname" "t128" "origin" "1392 240 308" "classname" "info_null" } { "light" "300" "target" "t128" "origin" "1392 240 376" "classname" "light" } { "targetname" "t129" "angle" "0" "origin" "552 -128 320" "classname" "monster_army" } { "target" "t129" "classname" "trigger_once" "model" "*45" } { "sounds" "1" "classname" "trigger_secret" "model" "*46" } { "sounds" "1" "classname" "trigger_secret" "model" "*47" } { "classname" "light" "origin" "1104 24 536" "light" "350" } { "spawnflags" "1" "classname" "func_door_secret" "angle" "270" "model" "*48" } { "light" "200" "origin" "1680 1552 320" "classname" "light" } { "classname" "light" "origin" "1312 1552 320" "light" "200" } { "classname" "item_spikes" "origin" "1480 1104 68" "spawnflags" "1" } { "classname" "item_spikes" "origin" "1760 -568 256" "spawnflags" "1" } { "classname" "item_spikes" "origin" "1232 -1200 416" } { "message" "This door is opened elsewhere..." "classname" "func_door" "sounds" "3" "angle" "180" "wait" "-1" "targetname" "t122" "speed" "35" "spawnflags" "2048" "model" "*49" } { "classname" "func_door" "angle" "0" "wait" "-1" "speed" "30" "spawnflags" "2048" "model" "*50" } { "classname" "light" "origin" "1496 1600 296" "light" "150 " } { "light" "150" "origin" "1568 1664 296" "classname" "light" } { "classname" "light" "origin" "1424 1664 296" "light" "150" } { "classname" "light" "origin" "1328 1424 296" "light" "200" } { "light" "250" "origin" "1696 1416 296" "classname" "light" } { "classname" "monster_army" "origin" "1592 1296 200" "angle" "270" } { "spawnflags" "768" "classname" "monster_demon1" "origin" "-96 576 320" "angle" "270" "targetname" "t73" "target" "t143" } { "classname" "path_corner" "origin" "1392 416 304" "targetname" "t131" "target" "t130" "spawnflags" "768" } { "origin" "1392 296 304" "classname" "path_corner" "targetname" "t130" "target" "t131" "spawnflags" "768" } { "classname" "monster_army" "origin" "1392 352 320" "angle" "270" "target" "t130" "spawnflags" "768" } { "target" "t132" "targetname" "t133" "origin" "296 -328 304" "classname" "path_corner" } { "target" "t133" "targetname" "t132" "classname" "path_corner" "origin" "472 -416 304" } { "spawnflags" "1" "target" "t132" "angle" "90" "origin" "472 -456 320" "classname" "monster_army" } { "spawnflags" "1" "targetname" "t89" "angle" "135" "origin" "1712 -784 376" "classname" "monster_army" } { "target" "t135" "spawnflags" "256" "targetname" "t134" "origin" "400 -1128 416" "classname" "path_corner" } { "target" "t134" "spawnflags" "256" "targetname" "t135" "classname" "path_corner" "origin" "400 -1248 416" } { "target" "t134" "spawnflags" "257" "angle" "90" "origin" "408 -1208 432" "classname" "monster_army" } { "targetname" "t101" "angle" "90" "origin" "-288 -24 488" "classname" "monster_army" "spawnflags" "768" } { "spawnflags" "768" "targetname" "t101" "classname" "monster_army" "origin" "136 -128 488" "angle" "90" } { "spawnflags" "1792" "origin" "-264 -24 464" "classname" "item_rockets" } { "spawnflags" "2048" "origin" "-240 -8 464" "classname" "item_spikes" } { "classname" "monster_ogre" "origin" "-304 -304 488" "angle" "225" "spawnflags" "769" } { "classname" "func_wall" "spawnflags" "768" "model" "*51" } { "classname" "trap_spikeshooter" "origin" "2048 -48 332" "angle" "270" "spawnflags" "769" "targetname" "t121" } { "origin" "2048 -476 332" "classname" "info_null" "targetname" "t136" } { "style" "32" "origin" "2048 -456 336" "classname" "light" "light" "800" "spawnflags" "1" "target" "t136" "targetname" "t137" } { "style" "32" "classname" "trigger_once" "spawnflags" "768" "target" "t137" "model" "*52" } { "classname" "monster_wizard" "origin" "672 328 384" "angle" "180" "spawnflags" "768" "targetname" "t138" } { "classname" "trigger_once" "target" "t138" "model" "*53" } { "style" "32" "classname" "light" "origin" "2004 -52 332" "light" "100" "spawnflags" "1" "targetname" "t137" } { "classname" "item_shells" "origin" "1416 224 300" "spawnflags" "768" } { "classname" "path_corner" "origin" "-344 136 304" "targetname" "t139" "target" "t140" "spawnflags" "768" } { "origin" "168 128 304" "classname" "path_corner" "target" "t139" "targetname" "t140" "spawnflags" "768" } { "classname" "monster_ogre" "origin" "-400 168 320" "spawnflags" "768" "target" "t139" } { "classname" "trap_spikeshooter" "origin" "2120 -256 332" "angle" "180" "spawnflags" "769" "targetname" "t121" } { "classname" "trap_spikeshooter" "origin" "1944 -456 332" "targetname" "t121" "angle" "90" "spawnflags" "769" } { "classname" "item_spikes" "origin" "-336 -80 470" "spawnflags" "768" } { "targetname" "t143" "classname" "trigger_teleport" "target" "t142" "spawnflags" "2" "model" "*54" } { "targetname" "t143" "classname" "trigger_teleport" "target" "t141" "spawnflags" "2" "model" "*55" } { "classname" "monster_demon1" "origin" "32 840 359" "angle" "270" "targetname" "t143" "spawnflags" "768" } { "angle" "270" "origin" "-192 840 359" "classname" "monster_demon1" "targetname" "t143" "spawnflags" "768" } { "classname" "info_teleport_destination" "origin" "80 216 303" "angle" "270" "targetname" "t141" } { "angle" "270" "origin" "-264 224 303" "classname" "info_teleport_destination" "targetname" "t142" } { "wait" "-1" "target" "t53" "health" "1" "classname" "func_button" "model" "*56" } { "spawnflags" "768" "angle" "270" "origin" "1408 1296 200" "classname" "monster_army" } { "classname" "item_shells" "origin" "772 -856 420" "spawnflags" "768" } { "spawnflags" "1792" "origin" "1248 -1128 420" "classname" "weapon_grenadelauncher" } { "spawnflags" "1793" "origin" "864 -312 440" "classname" "item_rockets" } { "classname" "trigger_once" "message" "Pass through the arch to exit..." "model" "*57" } { "mangle" "20 300 0" "classname" "info_intermission" "origin" "-224 424 512" } { "mangle" "20 45 0" "origin" "1048 -744 488" "classname" "info_intermission" } { "mangle" "20 270 0" "origin" "1104 424 528" "classname" "info_intermission" } { "mangle" "20 45 0" "origin" "1240 984 416" "classname" "info_intermission" } { "sounds" "1" "speed" "20" "classname" "func_button" "angle" "0" "wait" "-1" "target" "t144" "model" "*58" } { "classname" "light" "origin" "400 -1392 480" "light" "150" } { "classname" "func_door" "angle" "-2" "wait" "-1" "speed" "20" "sounds" "1" "targetname" "t144" "model" "*59" } { "classname" "trigger_secret" "model" "*60" } { "classname" "item_artifact_super_damage" "origin" "400 -1360 432" } { "classname" "item_spikes" "origin" "808 -632 192" "spawnflags" "2049" } { "classname" "item_health" "origin" "924 -632 192" "spawnflags" "2048" } { "classname" "weapon_supernailgun" "origin" "880 -616 192" "spawnflags" "1792" } { "classname" "ambient_drip" "origin" "842 978 344" } { "classname" "ambient_drip" "origin" "546 330 400" } { "classname" "info_player_coop" "origin" "1608 1664 264" "angle" "270" } { "angle" "270" "origin" "1392 1664 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "1496 1560 264" "angle" "270" } { "spawnflags" "256" "angle" "270" "origin" "232 -176 320" "classname" "monster_ogre" } { "spawnflags" "1280" "angle" "225" "origin" "-368 -312 480" "classname" "monster_knight" } { "spawnflags" "1792" "classname" "func_wall" "model" "*61" } { "origin" "1810 274 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1802 -102 200" } { "origin" "2050 -214 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "2002 -390 200" } { "origin" "1738 -398 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1346 -398 200" } { "origin" "1138 -542 200" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "882 -494 200" } { "classname" "ambient_swamp1" "origin" "1722 1090 176" } { "origin" "1242 1090 176" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "1106 642 192" } { "origin" "1346 242 192" "classname" "ambient_swamp2" } { "classname" "ambient_swamp1" "origin" "866 210 192" } { "classname" "ambient_swamp1" "origin" "1802 90 192" } { "origin" "1546 -398 192" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "2042 -310 192" } { "origin" "1178 -398 192" "classname" "ambient_swamp2" } { "classname" "ambient_swamp2" "origin" "1202 -678 192" } { "message" "the Grisly Grotto" "worldtype" "0" "classname" "worldspawn" "wad" "gfx/wizard.wad" "sounds" "5" } { "classname" "light" "origin" "464 480 1656" "light" "300" } { "light" "400" "origin" "712 296 1512" "classname" "light" } { "sounds" "3" "angle" "180" "classname" "func_door" "model" "*1" } { "angle" "0" "classname" "func_door" "model" "*2" } { "classname" "light_flame_small_yellow" "origin" "560 -112 1374" } { "origin" "848 -112 1374" "classname" "light_flame_small_yellow" } { "origin" "760 656 1536" "classname" "light" } { "light" "400" "origin" "834 498 1040" "classname" "light" } { "light" "200" "classname" "light" "origin" "944 728 1456" } { "classname" "light_flame_small_yellow" "origin" "1016 80 998" } { "origin" "392 80 998" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "680 1224 516" "light" "200" } { "light" "200" "origin" "704 992 516" "classname" "light" } { "light" "200" "origin" "696 1608 628" "classname" "light" } { "origin" "704 1368 588" "classname" "light" } { "origin" "816 1616 444" "classname" "light" } { "classname" "light" "origin" "712 1728 444" } { "origin" "592 1608 444" "classname" "light" } { "classname" "light" "origin" "624 1096 444" } { "light" "300" "origin" "432 1328 816" "classname" "light" } { "classname" "light" "origin" "696 1112 816" "light" "300" } { "classname" "light" "origin" "704 -80 960" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "818 18 948" "light" "200" } { "origin" "586 18 948" "classname" "light_torch_small_walltorch" "light" "200" } { "light" "200" "origin" "688 496 880" "classname" "light" } { "origin" "489 483 1356" "classname" "light_flame_large_yellow" } { "light" "200" "origin" "704 -120 1360" "classname" "light" } { "classname" "light" "origin" "1216 936 1560" "light" "200" } { "origin" "1294 826 1576" "classname" "light_flame_large_yellow" } { "sounds" "1" "targetname" "t1" "wait" "-1" "angle" "180" "classname" "func_door" "model" "*3" } { "angle" "0" "wait" "-1" "classname" "func_door" "model" "*4" } { "target" "t1" "classname" "trigger_once" "model" "*5" } { "map" "e1m5" "classname" "trigger_changelevel" "model" "*6" } { "wait" "-1" "angle" "0" "classname" "func_door" "speed" "50" "model" "*7" } { "classname" "info_player_start" "origin" "-256 2272 1240" "angle" "270" } { "targetname" "t23" "classname" "func_door" "angle" "180" "wait" "-1" "speed" "50" "sounds" "3" "model" "*8" } { "classname" "light" "origin" "696 704 820" } { "classname" "light" "origin" "704 776 672" "light" "200" } { "classname" "light" "origin" "360 904 520" "light" "200" } { "origin" "704 856 400" "classname" "light" "light" "200" } { "classname" "light" "origin" "944 880 416" "light" "150" } { "origin" "1056 1176 424" "classname" "light" "light" "200" } { "classname" "light" "origin" "1096 1408 360" } { "classname" "light" "origin" "416 1696 360" } { "origin" "328 1368 360" "classname" "light" "light" "200" } { "light" "200 " "classname" "light" "origin" "696 752 896" } { "light" "250" "origin" "798 1850 1024" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "642 1850 1024" "light" "250" } { "light" "200 " "origin" "700 1364 952" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "1094 1494 1064" } { "origin" "324 1104 1064" "classname" "light_flame_large_yellow" } { "light" "200 " "origin" "704 1660 952" "classname" "light" } { "sounds" "3" "classname" "func_door" "angle" "180" "wait" "-1" "targetname" "t2" "model" "*9" } { "sounds" "3" "classname" "func_door" "wait" "-1" "angle" "0" "targetname" "t4" "model" "*10" } { "classname" "trigger_once" "targetname" "t4" "target" "t7" "model" "*11" } { "classname" "trigger_once" "targetname" "t2" "target" "t7" "model" "*12" } { "dmg" "90" "speed" "200" "classname" "func_train" "target" "t5" "targetname" "t8" "model" "*13" } { "classname" "path_corner" "origin" "-359 1528 1316" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "-359 1528 880" "targetname" "t6" "target" "t5" "wait" "-1" } { "classname" "trigger_counter" "targetname" "t7" "target" "t8" "count" "2" "model" "*14" } { "targetname" "t11" "origin" "-96 1640 1256" "classname" "info_null" } { "targetname" "t9" "origin" "-416 1640 1256" "classname" "info_null" } { "light" "400" "target" "t9" "origin" "-396 1640 1256" "classname" "light" } { "light" "400" "target" "t11" "origin" "-116 1640 1256" "classname" "light" } { "classname" "light" "origin" "-328 1564 1532" } { "classname" "light_flame_small_yellow" "origin" "-88 1640 1514" } { "origin" "-424 1640 1514" "classname" "light_flame_small_yellow" } { "origin" "-248 1464 1154" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "-256 1808 1046" } { "light" "200" "origin" "-164 1732 1268" "classname" "light" } { "classname" "light" "origin" "-348 1732 1268" "light" "200" } { "light" "150" "origin" "-248 1500 1056" "classname" "light" } { "light" "150" "origin" "-256 1772 956" "classname" "light" } { "classname" "light" "origin" "-128 1636 920" "light" "150" } { "light" "150" "origin" "-124 1640 920" "classname" "light" } { "classname" "light" "origin" "-172 1524 920" "light" "150" } { "light" "150" "origin" "-284 1516 920" "classname" "light" } { "classname" "light" "origin" "-360 1580 920" "light" "150" } { "light" "75" "origin" "-360 1700 920" "classname" "light" } { "classname" "light" "origin" "72 1632 928" "light" "125" } { "light" "150" "origin" "80 1488 928" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "158 1308 1064" } { "classname" "light" "origin" "-192 1688 1380" "light" "100" } { "light" "100" "origin" "-192 1592 1380" "classname" "light" } { "classname" "light" "origin" "-320 1592 1380" "light" "100" } { "light" "100" "origin" "-320 1688 1380" "classname" "light" } { "classname" "light" "origin" "-384 1640 1452" "light" "125" } { "classname" "light" "origin" "-112 1640 1452" "light" "125" } { "light" "200" "origin" "-248 1504 1336" "classname" "light" } { "classname" "light" "origin" "-128 1640 1336" "light" "200" } { "light" "200" "origin" "-384 1640 1336" "classname" "light" } { "classname" "light" "origin" "696 1608 816" "light" "300" } { "light" "200" "classname" "light" "origin" "888 1328 424" } { "classname" "light" "origin" "160 1352 960" "light" "150" } { "light" "150" "origin" "368 1104 1000" "classname" "light" } { "classname" "light" "origin" "1048 1504 1000" "light" "150" } { "classname" "light" "origin" "992 992 1048" "light" "150" } { "classname" "light" "origin" "48 1384 1008" "light" "100" } { "light" "150" "origin" "1080 1144 1048" "classname" "light" } { "classname" "light" "origin" "968 824 976" "light" "150" } { "classname" "light" "origin" "896 1328 1000" "light" "150" } { "classname" "light" "origin" "368 1616 1000" "light" "175" } { "classname" "light" "origin" "256 1496 824" "light" "150" } { "light" "150" "origin" "256 1352 824" "classname" "light" } { "classname" "light" "origin" "856 1368 536" "light" "200" } { "light" "150" "origin" "552 1360 536" "classname" "light" } { "classname" "light" "origin" "872 1552 1056" "light" "150" } { "classname" "light" "origin" "1032 1056 904" "light" "150" } { "light" "150" "origin" "1080 1184 904" "classname" "light" } { "classname" "light" "origin" "864 848 904" "light" "150" } { "classname" "light" "origin" "312 1496 1016" "light" "175" } { "light" "200" "origin" "704 1368 808" "classname" "light" } { "light" "150" "origin" "464 816 904" "classname" "light" } { "light" "200" "origin" "944 888 800" "classname" "light" } { "light" "150" "origin" "888 1112 728" "classname" "light" } { "light" "175" "origin" "1008 1504 728" "classname" "light" } { "light" "200" "origin" "720 1848 1200" "classname" "light" } { "light" "200" "origin" "704 888 672" "classname" "light" } { "light" "175" "origin" "512 1456 1040" "classname" "light" } { "light" "150" "origin" "440 840 380" "classname" "light" } { "light" "150" "origin" "720 1848 1028" "classname" "light" } { "light" "150" "origin" "720 1936 1024" "classname" "light" } { "origin" "544 2128 984" "classname" "light" "light" "200" } { "light" "200" "origin" "712 1912 576" "classname" "light" } { "light" "300" "origin" "720 2544 856" "classname" "light" } { "light" "200" "origin" "888 2048 592" "classname" "light" } { "origin" "704 2496 1128" "classname" "light" } { "origin" "512 2048 976" "classname" "light" "light" "150" } { "origin" "952 2328 528" "classname" "light" "light" "200" } { "classname" "light" "origin" "700 2760 808" "light" "200" } { "classname" "light" "origin" "700 2800 616" "light" "200" } { "classname" "light" "origin" "584 2780 584" "light" "175" } { "light" "175" "origin" "808 2780 584" "classname" "light" } { "sounds" "3" "wait" "-1" "targetname" "t29" "classname" "func_door" "angle" "270" "model" "*15" } { "message" "This door is opened elsewhere..." "wait" "-1" "classname" "func_door" "angle" "90" "model" "*16" } { "classname" "light" "origin" "424 2304 1000" "light" "200" } { "light" "300" "origin" "696 2880 1062" "classname" "light_flame_small_yellow" } { "light" "200" "classname" "light" "origin" "864 2128 984" } { "classname" "light_flame_large_yellow" "origin" "702 2154 1228" "light" "0" } { "classname" "light" "origin" "832 2008 1136" "light" "200" } { "classname" "light" "origin" "584 2008 1136" "light" "200" } { "light" "200" "origin" "272 2016 1136" "classname" "light" } { "classname" "light" "origin" "272 2320 1136" "light" "150" } { "light" "150" "origin" "1104 2408 984" "classname" "light" } { "sounds" "2" "classname" "func_plat" "wait" "4" "model" "*17" } { "classname" "light" "origin" "700 2844 996" "light" "200" } { "classname" "light" "origin" "704 2216 1252" } { "origin" "936 2304 1252" "classname" "light" } { "classname" "light" "origin" "936 2536 1252" } { "light" "300" "classname" "light" "origin" "488 2536 1252" } { "origin" "488 2304 1252" "classname" "light" "light" "300" } { "light" "0" "origin" "998 2306 1228" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "998 2534 1228" "light" "0" } { "light" "0" "origin" "426 2534 1228" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "426 2306 1228" "light" "0" } { "classname" "light" "origin" "704 2152 984" "light" "200" } { "classname" "light_flame_small_yellow" "origin" "1160 2400 1038" "light" "250" } { "origin" "840 2536 630" "classname" "light_flame_small_yellow" "light" "250" } { "classname" "light_flame_small_yellow" "origin" "584 2544 630" "light" "250" } { "light" "250" "origin" "408 2304 694" "classname" "light_flame_small_yellow" } { "light" "200" "classname" "light" "origin" "960 2632 528" } { "classname" "light" "origin" "960 2480 528" "light" "150" } { "classname" "light" "origin" "456 2304 624" "light" "175" } { "classname" "light" "origin" "704 2416 576" "light" "250" } { "light" "150" "origin" "728 2184 528" "classname" "light" } { "classname" "light" "origin" "512 2176 528" "light" "150" } { "classname" "light" "origin" "832 2336 656" "light" "175" } { "light" "175" "origin" "592 2336 656" "classname" "light" } { "classname" "light" "origin" "808 2584 576" "light" "150" } { "light" "150" "origin" "616 2576 576" "classname" "light" } { "classname" "light_flame_small_yellow" "origin" "488 2712 694" "light" "250" } { "classname" "light" "origin" "488 2624 608" "light" "175" } { "classname" "light" "origin" "480 2464 608" "light" "175" } { "light" "250" "origin" "184 2184 1038" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "512 2096 1038" "light" "250" } { "classname" "light" "origin" "224 2184 976" "light" "150" } { "classname" "light" "origin" "848 2024 992" "light" "200" } { "classname" "light" "origin" "256 1992 1000" "light" "150" } { "classname" "light" "origin" "272 2376 1000" "light" "200" } { "classname" "light" "origin" "1112 2208 1032" "light" "150" } { "light" "0" "origin" "698 2860 1228" "classname" "light_flame_large_yellow" } { "origin" "700 2808 1252" "classname" "light" } { "light" "250" "origin" "472 2632 1062" "classname" "light" } { "classname" "light" "origin" "952 2632 1062" "light" "250" } { "light" "150" "origin" "952 2424 894" "classname" "light" } { "classname" "light" "origin" "480 2424 894" "light" "150" } { "light" "150" "origin" "896 2296 966" "classname" "light" } { "classname" "light" "origin" "704 2304 966" "light" "150" } { "light" "150" "origin" "552 2304 966" "classname" "light" } { "light" "250" "origin" "704 2184 406" "classname" "light" } { "light" "150" "origin" "712 2000 406" "classname" "light" } { "light" "200" "origin" "504 2224 400" "classname" "light" } { "light" "200" "origin" "960 2576 400" "classname" "light" } { "light" "150" "origin" "960 2400 400" "classname" "light" } { "light" "150" "origin" "808 1112 592" "classname" "light" } { "classname" "light" "origin" "600 1112 592" "light" "150" } { "light" "175" "origin" "1016 128 936" "classname" "light" } { "classname" "light" "origin" "392 128 936" "light" "175" } { "light" "150" "origin" "848 -64 1304" "classname" "light" } { "classname" "light" "origin" "560 -64 1304" "light" "150" } { "light" "175" "origin" "1248 832 1496" "classname" "light" } { "light" "150" "origin" "1096 872 1496" "classname" "light" } { "light" "150" "origin" "896 2208 976" "classname" "light" } { "classname" "light" "origin" "1096 200 1512" "light" "350" } { "light" "350" "origin" "264 192 1512" "classname" "light" } { "light" "175" "origin" "488 448 1264" "classname" "light" } { "origin" "1048 728 1456" "classname" "light" "light" "200" } { "light" "125" "origin" "1328 928 1448" "classname" "light" } { "light" "225" "origin" "696 672 1320" "classname" "light" } { "origin" "816 -56 1640" "classname" "light" } { "classname" "light" "origin" "584 -56 1640" } { "light" "175" "origin" "880 96 1376" "classname" "light" } { "classname" "light" "origin" "528 96 1376" "light" "175" } { "light" "200" "origin" "960 344 1072" "classname" "light" } { "classname" "light" "origin" "1120 264 1072" "light" "200" } { "light" "175" "origin" "1208 96 1016" "classname" "light" } { "light" "175" "origin" "1024 360 968" "classname" "light" } { "classname" "light" "origin" "328 336 968" "light" "150" } { "classname" "light" "origin" "416 424 1072" "light" "200" } { "light" "200" "origin" "296 256 1072" "classname" "light" } { "light" "150" "origin" "704 48 1040" "classname" "light" } { "light" "175" "origin" "384 464 976" "classname" "light" } { "classname" "light" "origin" "224 264 976" "light" "150" } { "light" "150" "origin" "952 2192 416" "classname" "light" } { "classname" "light" "origin" "1040 -464 1016" "light" "150" } { "sounds" "2" "spawnflags" "1" "classname" "func_plat" "model" "*18" } { "light" "250" "origin" "1072 -272 1262" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "1024 -272 1200" "light" "150" } { "light" "200" "origin" "624 -240 1328" "classname" "light" } { "light" "175" "origin" "1080 -624 1168" "classname" "light" } { "origin" "456 -576 1230" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "504 -576 1168" "light" "175" } { "origin" "624 -448 924" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "624 -704 924" } { "light" "125" "origin" "664 -448 880" "classname" "light" } { "classname" "light" "origin" "624 -488 880" "light" "125" } { "light" "125" "origin" "584 -448 880" "classname" "light" } { "classname" "light" "origin" "624 -408 880" "light" "125" } { "light" "125" "origin" "624 -664 880" "classname" "light" } { "classname" "light" "origin" "664 -704 880" "light" "125" } { "light" "125" "origin" "624 -744 880" "classname" "light" } { "classname" "light" "origin" "584 -704 880" "light" "125" } { "light" "250" "origin" "296 -96 968" "classname" "light" } { "light" "250" "origin" "1112 -96 968" "classname" "light" } { "light" "175" "origin" "1056 -224 968" "classname" "light" } { "light" "500" "origin" "-264 2120 1504" "classname" "light" } { "spawnflags" "2064" "angle" "0" "classname" "func_door" "wait" "-1" "model" "*19" } { "sounds" "3" "classname" "func_door" "angle" "180" "spawnflags" "2064" "wait" "-1" "model" "*20" } { "light" "200" "origin" "704 32 952" "classname" "light" } { "target" "t101" "spawnflags" "256" "targetname" "t23" "angle" "90" "origin" "-248 1560 1224" "classname" "monster_wizard" } { "target" "t23" "classname" "trigger_once" "model" "*21" } { "origin" "-280 1560 1348" "classname" "item_armor2" } { "origin" "-488 2112 1220" "classname" "item_health" } { "classname" "item_health" "origin" "-488 2064 1220" } { "spawnflags" "1536" "origin" "-272 1784 1156" "classname" "item_shells" } { "spawnflags" "256" "target" "t25" "targetname" "t24" "origin" "888 1640 1028" "classname" "path_corner" } { "spawnflags" "256" "target" "t24" "targetname" "t25" "classname" "path_corner" "origin" "624 1264 1028" } { "spawnflags" "256" "target" "t24" "origin" "928 1672 1028" "classname" "monster_wizard" } { "spawnflags" "2304" "target" "t26" "classname" "trigger_once" "model" "*22" } { "target" "t27" "targetname" "t28" "origin" "568 2040 928" "classname" "path_corner" } { "target" "t28" "targetname" "t27" "classname" "path_corner" "origin" "368 2044 928" } { "target" "t27" "origin" "472 2040 944" "classname" "monster_ogre" "spawnflags" "1" } { "sounds" "2" "target" "t29" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*23" } { "sounds" "3" "angle" "180" "classname" "func_door" "model" "*24" } { "angle" "0" "classname" "func_door" "model" "*25" } { "light" "175" "origin" "1112 2520 964" "classname" "light" } { "origin" "104 1308 892" "classname" "item_health" } { "spawnflags" "2048" "origin" "704 1344 936" "classname" "item_key1" "sounds" "1" } { "target" "t34" "angle" "180" "origin" "920 2040 544" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t35" "targetname" "t34" "origin" "864 2044 528" "classname" "path_corner" } { "target" "t37" "targetname" "t35" "classname" "path_corner" "origin" "704 2048 528" } { "target" "t34" "targetname" "t36" "origin" "704 2048 528" "classname" "path_corner" } { "target" "t36" "targetname" "t37" "classname" "path_corner" "origin" "704 1808 528" } { "targetname" "t38" "angle" "270" "origin" "456 2476 544" "classname" "monster_ogre" } { "target" "t38" "classname" "trigger_once" "model" "*26" } { "targetname" "t29" "angle" "0" "origin" "336 2272 952" "classname" "monster_knight" "spawnflags" "768" } { "targetname" "t39" "spawnflags" "1" "wait" "-1" "angle" "-2" "classname" "func_door" "sounds" "1" "model" "*27" } { "targetname" "t39" "angle" "270" "origin" "712 2540 448" "classname" "monster_ogre" } { "target" "t39" "classname" "trigger_once" "model" "*28" } { "classname" "light" "origin" "712 2544 440" "light" "200" } { "classname" "item_health" "origin" "1064 2184 920" "spawnflags" "1024" } { "spawnflags" "1" "origin" "1128 2184 920" "classname" "item_health" } { "classname" "item_spikes" "origin" "816 2840 920" } { "origin" "816 2800 920" "classname" "item_spikes" } { "spawnflags" "256" "classname" "monster_wizard" "origin" "1656 1496 968" "angle" "180" "target" "t41" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t40" "targetname" "t39" "model" "*29" } { "classname" "info_teleport_destination" "origin" "984 1496 1000" "angle" "180" "targetname" "t40" } { "spawnflags" "256" "classname" "path_corner" "origin" "912 1496 1000" "targetname" "t41" "target" "t42" } { "spawnflags" "256" "origin" "528 1368 1000" "classname" "path_corner" "targetname" "t42" "target" "t41" } { "classname" "item_health" "origin" "408 2640 520" } { "classname" "item_shells" "origin" "456 2672 520" "spawnflags" "1" } { "angle" "0" "origin" "80 864 968" "classname" "monster_wizard" "target" "t44" } { "targetname" "t119" "spawnflags" "2" "classname" "trigger_teleport" "target" "t45" "model" "*30" } { "classname" "info_teleport_destination" "origin" "432 856 952" "angle" "45" "targetname" "t45" } { "classname" "path_corner" "origin" "496 872 952" "target" "t43" "targetname" "t44" } { "origin" "872 1056 952" "classname" "path_corner" "targetname" "t43" "target" "t44" } { "classname" "trigger_once" "spawnflags" "1792" "target" "t39" "model" "*31" } { "spawnflags" "1024" "classname" "monster_knight" "origin" "1168 56 904" "angle" "135" "target" "t49" "targetname" "t67" } { "classname" "monster_ogre" "origin" "1800 224 920" "angle" "180" "target" "t116" "spawnflags" "256" } { "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t49" "lip" "-24" "model" "*32" } { "wait" "-1" "angle" "-1" "classname" "func_door" "spawnflags" "1" "targetname" "t39" "lip" "-24" "model" "*33" } { "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t29" "lip" "-24" "model" "*34" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t46" "model" "*35" } { "classname" "info_teleport_destination" "origin" "1104 232 880" "angle" "180" "targetname" "t46" } { "classname" "path_corner" "origin" "1064 256 880" "target" "t47" "targetname" "t48" "spawnflags" "256" } { "origin" "312 232 880" "classname" "path_corner" "targetname" "t47" "target" "t48" "spawnflags" "256" } { "classname" "info_teleport_destination" "origin" "704 -40 1256" "angle" "90" "targetname" "t50" } { "classname" "trigger_once" "target" "t52" "model" "*36" } { "spawnflags" "2" "classname" "trigger_teleport" "target" "t50" "targetname" "t52" "model" "*37" } { "angle" "90" "origin" "570 -898 1300" "classname" "monster_wizard" "targetname" "t52" } { "classname" "item_shells" "origin" "216 120 880" "spawnflags" "1" } { "classname" "item_health" "origin" "192 232 880" } { "origin" "192 192 880" "classname" "item_health" "spawnflags" "1024" } { "classname" "item_shells" "origin" "-216 1464 888" } { "classname" "item_health" "origin" "816 1160 512" "spawnflags" "1024" } { "spawnflags" "1" "origin" "816 1120 512" "classname" "item_health" } { "classname" "monster_wizard" "origin" "944 840 956" "angle" "135" "target" "t53" "targetname" "t64" } { "classname" "trigger_once" "target" "t64" "model" "*38" } { "classname" "monster_knight" "origin" "704 392 1280" "angle" "270" "target" "t65" "spawnflags" "1" } { "classname" "path_corner" "origin" "704 208 1264" "targetname" "t65" "target" "t66" } { "origin" "704 496 1264" "classname" "path_corner" "targetname" "t66" "target" "t65" } { "classname" "trigger_once" "target" "t67" "model" "*39" } { "sounds" "1" "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t72" "model" "*40" } { "sounds" "1" "classname" "func_door" "wait" "-1" "angle" "-2" "targetname" "t72" "model" "*41" } { "classname" "trigger_once" "target" "t72" "model" "*42" } { "classname" "info_null" "origin" "852 -580 820" "targetname" "t73" } { "classname" "light" "origin" "856 -584 936" "light" "400" "target" "t73" } { "classname" "light" "origin" "920 -448 744" "light" "150" } { "light" "150" "origin" "760 -448 744" "classname" "light" } { "classname" "light" "origin" "552 -424 744" "light" "150" } { "light" "150" "origin" "560 -728 744" "classname" "light" } { "classname" "light" "origin" "776 -712 744" "light" "150" } { "light" "150" "origin" "936 -712 744" "classname" "light" } { "classname" "path_corner" "origin" "652 -576 952" "targetname" "t75" "target" "t74" } { "origin" "908 -576 952" "classname" "path_corner" "targetname" "t74" "target" "t75" } { "classname" "monster_ogre" "origin" "816 -260 952" "angle" "270" "targetname" "t72" } { "classname" "monster_ogre" "origin" "724 -260 952" "angle" "270" "targetname" "t72" "spawnflags" "256" } { "classname" "item_health" "origin" "632 -548 820" "spawnflags" "3072" } { "origin" "672 -548 820" "classname" "item_health" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t76" "model" "*43" } { "sounds" "1" "classname" "func_door" "angle" "-1" "wait" "-1" "targetname" "t76" "model" "*44" } { "light" "150" "origin" "1040 -712 1016" "classname" "light" } { "origin" "1112 -576 942" "classname" "light_flame_small_yellow" } { "classname" "light" "origin" "1064 -576 896" "light" "150" } { "classname" "light" "origin" "888 -80 968" "light" "175" } { "light" "175" "origin" "512 -80 968" "classname" "light" } { "classname" "item_armor2" "origin" "1184 -96 920" } { "classname" "monster_ogre" "origin" "392 8 912" "angle" "315" "targetname" "t77" "spawnflags" "256" } { "classname" "trigger_once" "target" "t77" "model" "*45" } { "classname" "item_health" "origin" "336 -224 888" "spawnflags" "1" } { "classname" "item_spikes" "origin" "968 16 888" "spawnflags" "1" } { "classname" "item_health" "origin" "560 2808 516" "spawnflags" "1" } { "classname" "path_corner" "origin" "1056 -384 824" "targetname" "t78" "target" "t79" "spawnflags" "256" } { "origin" "1056 -736 824" "classname" "path_corner" "targetname" "t79" "target" "t78" "spawnflags" "256" } { "classname" "monster_ogre" "origin" "1064 -656 840" "angle" "90" "target" "t78" "spawnflags" "257" } { "angle" "90" "origin" "848 -880 952" "classname" "monster_ogre" "targetname" "t72" } { "classname" "item_shells" "origin" "1160 16 1248" } { "classname" "item_health" "origin" "280 64 1248" } { "classname" "item_rockets" "origin" "648 -256 928" "spawnflags" "1025" } { "classname" "item_spikes" "origin" "648 -304 1248" } { "origin" "696 -304 1248" "classname" "item_spikes" } { "classname" "light_flame_small_yellow" "origin" "768 -352 1230" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*46" } { "target" "t83" "classname" "trigger_multiple" "wait" ".8" "model" "*47" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*48" } { "target" "t83" "classname" "trigger_multiple" "wait" ".8" "model" "*49" } { "target" "t83" "wait" ".8" "classname" "trigger_multiple" "model" "*50" } { "targetname" "t83" "classname" "trap_spikeshooter" "origin" "1108 -576 1140" "spawnflags" "1" "angle" "180" } { "targetname" "t83" "angle" "90" "spawnflags" "1" "origin" "768 -796 1140" "classname" "trap_spikeshooter" } { "origin" "1112 -576 1230" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "768 -800 1230" } { "classname" "light" "origin" "712 -756 1168" "light" "175" } { "light" "175" "origin" "768 -424 1168" "classname" "light" } { "light" "175" "origin" "888 -744 956" "classname" "light" } { "classname" "light" "origin" "888 -408 956" "light" "175" } { "origin" "384 -224 888" "classname" "item_shells" } { "origin" "584 1784 920" "classname" "item_health" } { "origin" "832 2064 920" "classname" "item_shells" } { "target" "t72" "classname" "trigger_once" "model" "*51" } { "target" "t85" "targetname" "t84" "origin" "1560 216 896" "classname" "path_corner" } { "target" "t48" "targetname" "t85" "classname" "path_corner" "origin" "1456 216 896" } { "origin" "704 1368 516" "classname" "weapon_supernailgun" } { "spawnflags" "1" "origin" "184 1928 920" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "656 1816 528" "spawnflags" "768" } { "classname" "item_shells" "origin" "1072 -800 820" "spawnflags" "1024" } { "classname" "monster_ogre" "origin" "840 -40 1276" "angle" "180" "targetname" "t86" "spawnflags" "768" } { "classname" "trigger_once" "target" "t86" "model" "*52" } { "classname" "light" "origin" "472 -576 876" "light" "150" } { "classname" "item_shells" "origin" "656 680 1256" "spawnflags" "1536" } { "angle" "270" "origin" "880 2224 536" "classname" "monster_knight" "spawnflags" "256" } { "angle" "180" "origin" "1112 2424 944" "classname" "monster_ogre" "spawnflags" "1281" } { "targetname" "t88" "target" "t87" "origin" "360 384 880" "classname" "path_corner" "spawnflags" "1280" } { "target" "t88" "targetname" "t87" "classname" "path_corner" "origin" "504 160 880" "spawnflags" "1280" } { "target" "t87" "angle" "315" "origin" "384 320 896" "classname" "monster_knight" "spawnflags" "1280" } { "spawnflags" "257" "targetname" "t86" "angle" "0" "origin" "376 120 1272" "classname" "monster_ogre" } { "origin" "776 1368 916" "classname" "item_shells" "spawnflags" "1024" } { "classname" "item_spikes" "origin" "184 1968 920" "spawnflags" "1" } { "classname" "monster_wizard" "origin" "312 936 944" "angle" "45" "spawnflags" "769" } { "classname" "monster_knight" "origin" "704 -80 908" "angle" "90" } { "angle" "0" "origin" "568 -56 1276" "classname" "monster_ogre" "targetname" "t86" "spawnflags" "768" } { "spawnflags" "1536" "targetname" "t90" "target" "t89" "origin" "720 1696 924" "classname" "path_corner" } { "spawnflags" "1536" "target" "t90" "targetname" "t89" "classname" "path_corner" "origin" "720 1416 924" } { "spawnflags" "1537" "target" "t90" "origin" "704 1784 948" "classname" "monster_ogre" } { "classname" "func_door_secret" "angle" "0" "spawnflags" "1" "targetname" "t91" "model" "*53" "t_length" "73" // svdijk -- added to prevent z-fighting } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*54" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*55" } { "classname" "func_button" "wait" "-1" "angle" "-2" "target" "t92" "model" "*56" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t92" "model" "*57" } { "classname" "func_button" "wait" "-1" "angle" "-2" "target" "t92" "model" "*58" } { "classname" "trigger_counter" "count" "5" "target" "t91" "targetname" "t92" "model" "*59" } { "classname" "light" "origin" "680 -920 1144" "light" "150" } { "classname" "item_spikes" "origin" "752 -876 928" "spawnflags" "1" } { "spawnflags" "3" "angle" "0" "classname" "func_door_secret" "targetname" "t91" "model" "*60" "t_length" "73" // svdijk -- added to prevent z-fighting } { "light" "150" "origin" "680 -256 1144" "classname" "light" } { "classname" "trigger_once" "spawnflags" "1792" "target" "t72" "model" "*61" } { "classname" "trigger_secret" "sounds" "1" "targetname" "t8" "model" "*62" } { "angle" "270" "origin" "704 624 1280" "classname" "monster_knight" "spawnflags" "1" } { "angle" "225" "origin" "1016 -440 1128" "classname" "monster_knight" } { "angle" "180" "origin" "1024 -728 1128" "classname" "monster_knight" } { "spawnflags" "256" "angle" "180" "origin" "1008 -568 1128" "classname" "monster_knight" } { "spawnflags" "256" "classname" "monster_knight" "origin" "304 2312 952" "angle" "0" "targetname" "t29" } { "spawnflags" "1025" "classname" "monster_knight" "origin" "272 136 896" "angle" "45" } { "classname" "monster_wizard" "origin" "784 -576 960" "angle" "0" "target" "t74" "spawnflags" "1" } { "classname" "item_health" "origin" "732 -936 928" } { "origin" "772 -936 928" "classname" "item_health" } { "spawnflags" "256" "classname" "monster_knight" "origin" "704 -248 1272" "angle" "0" } { "classname" "path_corner" "origin" "1328 928 1396" "targetname" "t93" "target" "t94" "spawnflags" "512" } { "origin" "1176 928 1396" "classname" "path_corner" "target" "t93" "targetname" "t94" "spawnflags" "512" } { "classname" "monster_knight" "origin" "1192 884 1412" "angle" "0" "target" "t93" "spawnflags" "513" } { "classname" "monster_knight" "origin" "704 2376 944" "angle" "90" } { "classname" "monster_knight" "origin" "888 2312 944" "angle" "180" "targetname" "t95" } { "angle" "0" "origin" "512 2304 944" "classname" "monster_knight" "targetname" "t95" "spawnflags" "768" } { "classname" "trigger_once" "target" "t95" "model" "*63" } { "spawnflags" "256" "angle" "315" "origin" "728 2312 536" "classname" "monster_knight" } { "light" "200" "origin" "1296 1528 936" "classname" "light" } { "light" "250" "origin" "1432 1360 982" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "1400 1360 920" "classname" "light" } { "light" "200" "origin" "1248 1344 680" "classname" "light" } { "lip" "-384" "wait" "-1" "angle" "90" "classname" "func_door" "targetname" "t98" "model" "*64" } { "light" "150" "origin" "1152 1328 584" "classname" "light" } { "origin" "1376 1480 864" "classname" "item_health" } { "sounds" "1" "classname" "trigger_secret" "model" "*65" } { "classname" "func_button" "sounds" "1" "angle" "0" "wait" "-1" "target" "t97" "model" "*66" } { "classname" "func_button" "wait" "-1" "angle" "0" "sounds" "1" "target" "t97" "model" "*67" } { "classname" "trigger_counter" "targetname" "t97" "target" "t98" "model" "*68" } { "classname" "light" "origin" "880 -888 968" "light" "150" } { "light" "150" "origin" "880 -264 968" "classname" "light" } { "angle" "180" "origin" "1112 2344 944" "classname" "monster_ogre" "spawnflags" "769" } { "angle" "270" "origin" "1120 880 1412" "classname" "monster_ogre" "spawnflags" "257" } { "map" "e1m8" "classname" "trigger_changelevel" "model" "*69" } { "light" "175" "origin" "824 -756 1168" "classname" "light" } { "classname" "light" "origin" "1080 -528 1168" "light" "175" } { "classname" "monster_wizard" "origin" "672 -392 1024" "angle" "315" "spawnflags" "257" } { "classname" "monster_knight" "origin" "1008 -656 1128" "angle" "180" "spawnflags" "768" } { "origin" "520 1064 440" "classname" "air_bubbles" } { "classname" "item_spikes" "origin" "16 1432 892" } { "classname" "trigger_once" "message" "A secret cave has opened..." "targetname" "t98" "model" "*70" } { "target" "t4" "health" "1" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*71" } { "target" "t2" "health" "1" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*72" } { "target" "t49" "spawnflags" "769" "angle" "135" "origin" "1208 128 904" "classname" "monster_demon1" } { "spawnflags" "769" "angle" "45" "origin" "288 160 896" "classname" "monster_demon1" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "692 -884 952" "angle" "90" } { "classname" "monster_ogre" "origin" "-312 1648 1372" "angle" "90" "targetname" "t23" "spawnflags" "768" } { "angle" "90" "origin" "-192 1648 1372" "classname" "monster_ogre" "targetname" "t23" "spawnflags" "768" } { "classname" "monster_ogre" "origin" "704 1288 540" "angle" "270" "spawnflags" "768" } { "targetname" "t101" "target" "t106" "spawnflags" "770" "classname" "trigger_teleport" "model" "*73" } { "spawnflags" "768" "targetname" "t101" "angle" "270" "origin" "-256 2424 1288" "classname" "monster_wizard" } { "targetname" "t101" "origin" "-248 2440 1280" "classname" "trigger_relay" } { "targetname" "t29" "spawnflags" "256" "angle" "0" "origin" "144 2648 1024" "classname" "monster_wizard" } { "targetname" "t29" "spawnflags" "768" "classname" "monster_wizard" "origin" "144 2592 1024" "angle" "0" } { "targetname" "t29" "spawnflags" "768" "angle" "0" "origin" "144 2536 1024" "classname" "monster_wizard" } { "targetname" "t29" "target" "t102" "spawnflags" "258" "classname" "trigger_teleport" "model" "*74" } { "targetname" "t29" "target" "t103" "spawnflags" "770" "classname" "trigger_teleport" "model" "*75" } { "targetname" "t29" "target" "t104" "spawnflags" "770" "classname" "trigger_teleport" "model" "*76" } { "angle" "270" "targetname" "t102" "spawnflags" "256" "origin" "704 2656 1008" "classname" "info_teleport_destination" } { "angle" "270" "targetname" "t103" "spawnflags" "768" "classname" "info_teleport_destination" "origin" "920 2520 1008" } { "angle" "0" "targetname" "t104" "spawnflags" "768" "origin" "592 2192 1008" "classname" "info_teleport_destination" } { "sounds" "1" "classname" "func_door" "angle" "0" "wait" "-1" "speed" "150" "targetname" "t105" "model" "*77" } { "classname" "monster_demon1" "origin" "1056 -880 1128" "angle" "90" "spawnflags" "768" "targetname" "t105" } { "classname" "trigger_once" "spawnflags" "768" "target" "t105" "model" "*78" } { "classname" "light" "origin" "1056 -920 1184" "light" "125" } { "classname" "trigger_relay" "origin" "1104 -864 1120" "target" "t105" } { "classname" "monster_ogre" "origin" "1120 768 1416" "angle" "180" "spawnflags" "769" } { "classname" "air_bubbles" "origin" "884 1616 440" } { "targetname" "t106" "spawnflags" "768" "angle" "270" "origin" "-264 2232 1296" "classname" "info_teleport_destination" } { "classname" "path_corner" "origin" "568 1984 928" "targetname" "t107" "target" "t108" "spawnflags" "256" } { "origin" "424 1960 928" "classname" "path_corner" "target" "t107" "spawnflags" "256" "targetname" "t111" } { "classname" "path_corner" "origin" "704 2024 928" "targetname" "t108" "target" "t109" "spawnflags" "256" } { "origin" "712 1712 928" "classname" "path_corner" "targetname" "t109" "target" "t110" "spawnflags" "256" } { "classname" "path_corner" "origin" "712 1416 928" "targetname" "t110" "target" "t109" "spawnflags" "256" } { "classname" "func_door" "angle" "-2" "wait" "-1" "lip" "-24" "targetname" "t26" "spawnflags" "2304" "model" "*79" } { "classname" "monster_ogre" "origin" "240 2048 944" "angle" "0" "spawnflags" "257" "target" "t111" } { "target" "t23" "spawnflags" "1792" "classname" "trigger_once" "model" "*80" } { "classname" "monster_knight" "origin" "576 2768 536" "angle" "0" "spawnflags" "256" } { "spawnflags" "256" "angle" "180" "origin" "824 2776 536" "classname" "monster_knight" } { "classname" "monster_wizard" "origin" "704 -1032 1024" "angle" "90" "spawnflags" "256" "targetname" "t52" } { "angle" "90" "origin" "760 -1032 1024" "classname" "monster_wizard" "spawnflags" "768" "targetname" "t114" } { "classname" "monster_wizard" "origin" "816 -1032 1024" "angle" "90" "spawnflags" "768" "targetname" "t114" } { "targetname" "t52" "classname" "trigger_teleport" "spawnflags" "258" "target" "t112" "model" "*81" } { "classname" "trigger_teleport" "spawnflags" "770" "target" "t113" "targetname" "t114" "model" "*82" } { "targetname" "t114" "classname" "trigger_teleport" "spawnflags" "770" "target" "t115" "model" "*83" } { "classname" "info_teleport_destination" "origin" "896 224 1352" "angle" "135" "spawnflags" "256" "targetname" "t112" } { "classname" "info_teleport_destination" "origin" "488 1648 1016" "angle" "315" "spawnflags" "768" "targetname" "t113" } { "classname" "trigger_once" "spawnflags" "768" "target" "t114" "model" "*84" } { "classname" "info_teleport_destination" "origin" "800 904 928" "angle" "90" "spawnflags" "768" "targetname" "t115" } { "angle" "270" "origin" "-256 2232 1242" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "-256 2096 1218" "classname" "weapon_supershotgun" } { "angle" "270" "origin" "704 424 1266" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 2488 946" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 1968 546" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "704 104 898" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "704 1568 938" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "704 1344 912" "classname" "weapon_rocketlauncher" } { "angle" "0" "origin" "712 -576 840" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "944 -576 816" "classname" "weapon_nailgun" } { "angle" "180" "origin" "1064 -576 1128" "classname" "info_player_deathmatch" } { "spawnflags" "1792" "origin" "696 584 1256" "classname" "weapon_grenadelauncher" } { "classname" "light" "origin" "316 804 780" "light" "150" } { "classname" "light" "origin" "316 804 644" "light" "75" } { "classname" "item_rockets" "origin" "298 710 706" "spawnflags" "1" } { "classname" "item_shells" "origin" "988 -928 1104" "spawnflags" "1" } { "classname" "item_health" "origin" "-56 2112 1220" "spawnflags" "3584" } { "classname" "item_health" "origin" "-56 2072 1220" "spawnflags" "2305" } { "spawnflags" "1" "origin" "584 2416 512" "classname" "item_spikes" } { "origin" "688 1392 516" "classname" "item_spikes" } { "classname" "item_artifact_invulnerability" "origin" "712 2312 948" "spawnflags" "1792" } { "origin" "32 1392 916" "classname" "item_artifact_envirosuit" } { "mangle" "26 310 0" "origin" "384 488 1552" "classname" "info_intermission" } { "light" "100" "origin" "800 1160 464" "classname" "light" } { "classname" "light" "origin" "608 1160 464" "light" "100" } { "light" "100" "origin" "604 1472 464" "classname" "light" } { "target" "t40" "classname" "trigger_teleport" "model" "*85" } { "mangle" "-20 75 0" "origin" "456 2144 568" "classname" "info_intermission" } { "mangle" "10 80 0" "origin" "464 1032 1000" "classname" "info_intermission" } { "mangle" "20 135 0" "origin" "1080 -752 1008" "classname" "info_intermission" } { "classname" "trigger_secret" "model" "*86" } { "classname" "path_corner" "origin" "1632 216 896" "targetname" "t116" "target" "t84" } { "classname" "item_spikes" "origin" "1200 48 872" "spawnflags" "1" } { "classname" "item_spikes" "origin" "928 2664 320" "spawnflags" "1" } { "classname" "item_shells" "origin" "1240 768 1384" "spawnflags" "1" } { "classname" "item_shells" "origin" "-88 2160 1224" "spawnflags" "2049" } { "classname" "info_player_coop" "origin" "-208 2272 1240" "angle" "270" } { "angle" "270" "origin" "-304 2272 1240" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-352 2272 1240" "angle" "270" } { "light" "200" "origin" "1288 1648 956" "classname" "light" } { "classname" "item_spikes" "origin" "-264 1464 888" } { "spawnflags" "1792" "origin" "1296 1488 888" "classname" "item_artifact_invisibility" } { "spawnflags" "1792" "classname" "func_wall" "model" "*87" } { "classname" "func_wall" "spawnflags" "1792" "model" "*88" } { "target" "t118" "targetname" "t117" "origin" "-176 1640 888" "classname" "path_corner" } { "targetname" "t118" "target" "t117" "classname" "path_corner" "origin" "-320 1640 888" } { "target" "t117" "origin" "-256 1632 904" "classname" "monster_knight" "spawnflags" "1" } { "origin" "1376 1424 864" "classname" "weapon_grenadelauncher" } { "spawnflags" "1" "targetname" "t120" "target" "t119" "classname" "trigger_counter" "model" "*89" } { "target" "t120" "targetname" "t53" "classname" "trigger_once" "model" "*90" } { "target" "t120" "targetname" "t39" "classname" "trigger_once" "model" "*91" } { "classname" "light" "origin" "480 2568 568" "light" "125" } { "origin" "162 1482 976" "classname" "ambient_drip" } { "origin" "786 1010 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "778 1210 584" } { "origin" "594 1202 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "602 1010 584" } { "origin" "786 1514 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "794 1698 584" } { "origin" "618 1690 584" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "618 1522 584" } { "origin" "698 1362 584" "classname" "ambient_drip" } { "origin" "714 1970 592" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "898 2170 592" } { "origin" "938 2346 592" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "682 2298 592" } { "origin" "458 2306 592" "classname" "ambient_drip" } { "origin" "458 1690 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "322 1506 880" } { "origin" "338 1226 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "466 1090 880" } { "origin" "394 882 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "674 810 880" } { "origin" "914 818 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "922 1034 880" } { "origin" "1082 1266 880" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "994 1442 880" } { "origin" "898 1714 880" "classname" "ambient_drip" } { "origin" "706 1362 1080" "classname" "ambient_drip" } { "origin" "1194 1522 1032" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "1314 1354 1032" } { "origin" "442 354 920" "classname" "ambient_swamp1" } { "origin" "978 314 920" "classname" "ambient_swamp2" } { "message" "the Ogre Citadel" "sounds" "8" "wad" "gfx/wizard.wad" "classname" "worldspawn" "worldtype" "0" } { "origin" "160 -160 120" "classname" "light" } { "angle" "90" "origin" "-256 -1952 280" "classname" "info_player_start" } { "classname" "light" "origin" "160 -392 248" "light" "200" } { "classname" "light" "origin" "160 -648 184" } { "classname" "light" "origin" "-56 -392 248" "light" "200" } { "classname" "light" "origin" "376 -392 248" "light" "200" } { "classname" "light" "origin" "288 -416 -72" "light" "200" } { "classname" "light" "origin" "32 -416 -72" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "10 -270 148" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "314 -270 148" "light" "250" } { "classname" "light" "origin" "-264 -440 248" "light" "200" } { "classname" "light" "origin" "584 -440 248" "light" "200" } { "classname" "light" "origin" "544 -648 248" } { "light" "150" "origin" "648 -456 -184" "classname" "light" } { "origin" "376 -800 184" "classname" "light" } { "classname" "light" "origin" "-152 -752 184" "light" "250" } { "classname" "light" "origin" "-232 -592 184" "light" "250" } { "classname" "light" "origin" "160 112 184" } { "classname" "light" "origin" "160 352 120" } { "classname" "light" "origin" "160 216 -48" "light" "120" } { "classname" "light" "origin" "160 16 -48" "light" "120" } { "classname" "light" "origin" "160 544 144" "light" "225" } { "classname" "light" "origin" "480 576 88" } { "classname" "light" "origin" "480 448 88" } { "classname" "light" "origin" "480 576 168" "light" "250" } { "classname" "light" "origin" "480 448 168" "light" "250" } { "classname" "light" "origin" "160 896 312" "light" "350" } { "classname" "light" "origin" "288 896 312" "light" "100" } { "classname" "light" "origin" "32 896 312" "light" "100" } { "classname" "light" "origin" "160 1008 312" "light" "100" } { "classname" "light" "origin" "160 784 312" "light" "100" } { "classname" "light" "origin" "392 120 184" "light" "350" } { "classname" "light" "origin" "568 208 184" "light" "350" } { "classname" "light" "origin" "720 480 184" } { "classname" "light" "origin" "640 632 184" } { "classname" "light" "origin" "472 1152 56" } { "classname" "light" "origin" "512 896 152" } { "origin" "800 800 184" "classname" "light" } { "light" "200" "origin" "632 1264 -40" "classname" "light" } { "origin" "800 1032 184" "classname" "light" } { "origin" "760 1472 64" "classname" "light" } { "light" "200" "origin" "544 1416 56" "classname" "light" } { "origin" "672 1256 184" "classname" "light" "light" "200" } { "light" "200" "origin" "1024 1272 184" "classname" "light" } { "light" "200" "origin" "992 1440 184" "classname" "light" } { "origin" "1240 488 184" "classname" "light" } { "origin" "1280 136 176" "classname" "light" } { "origin" "160 1304 136" "classname" "light" } { "origin" "160 1648 256" "classname" "light" "light" "200" } { "origin" "240 1600 256" "classname" "light" "light" "200" } { "origin" "16 1616 168" "classname" "light" "light" "200" } { "light" "200" "origin" "-120 1304 40" "classname" "light" } { "origin" "-352 1144 16" "classname" "light" "light" "250" } { "origin" "-56 1096 64" "classname" "light" } { "light" "200" "origin" "-56 1152 280" "classname" "light" } { "light" "350" "origin" "-440 1144 200" "classname" "light" } { "light" "200" "origin" "-352 1336 -72" "classname" "light" } { "origin" "-488 368 56" "classname" "light" "light" "250" } { "light" "350" "origin" "-488 896 136" "classname" "light" } { "origin" "-216 896 184" "classname" "light" "light" "250" } { "origin" "-128 536 168" "classname" "light" "light" "200" } { "light" "150" "origin" "-104 480 32" "classname" "light" } { "light" "150" "origin" "-208 936 56" "classname" "light" } { "light" "150" "origin" "-208 736 32" "classname" "light" } { "origin" "-344 64 184" "classname" "light" } { "light" "350" "origin" "-648 384 184" "classname" "light" } { "light" "350" "origin" "-488 688 184" "classname" "light" } { "light" "150" "origin" "-680 496 -36" "classname" "light" } { "light" "350" "origin" "-600 1104 96" "classname" "light" } { "origin" "-824 896 168" "classname" "light" } { "origin" "-896 600 160" "classname" "light" } { "target" "t1" "classname" "trigger_teleport" "model" "*1" } { "spawnflags" "1792" "targetname" "t1" "origin" "-448 264 -56" "classname" "info_teleport_destination" "angle" "45" } { "light" "250" "origin" "-168 1320 160" "classname" "light" } { "origin" "-24 896 184" "classname" "light" } { "origin" "-104 896 184" "classname" "light" "light" "250" } { "spawnflags" "2" "origin" "-680 880 48" "classname" "item_health" } { "angle" "90" "origin" "-896 512 24" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "-184 560 128" "classname" "info_player_deathmatch" } { "angle" "270" "origin" "160 1640 160" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "1272 112 80" "classname" "info_player_deathmatch" } { "angle" "90" "origin" "176 -784 24" "classname" "info_player_deathmatch" } { "spawnflags" "1" "origin" "208 -160 0" "classname" "item_rockets" } { "origin" "64 464 0" "classname" "item_health" } { "origin" "120 464 0" "classname" "item_health" } { "spawnflags" "1" "origin" "-8 840 64" "classname" "item_health" } { "spawnflags" "1" "origin" "-8 952 64" "classname" "item_health" } { "spawnflags" "9" "origin" "568 880 0" "classname" "item_weapon" } { "origin" "456 1104 -88" "classname" "item_health" } { "spawnflags" "1" "origin" "664 1272 -88" "classname" "item_shells" } { "angle" "225" "origin" "888 1312 120" "classname" "info_player_deathmatch" } { "origin" "1328 168 56" "classname" "item_health" } { "origin" "1328 128 56" "classname" "item_health" } { "origin" "1328 208 56" "classname" "item_health" } { "spawnflags" "1" "origin" "816 1472 0" "classname" "item_shells" } { "light" "200" "origin" "-64 -120 -56" "classname" "light" } { "light" "200" "origin" "-296 -160 -56" "classname" "light" } { "light" "200" "origin" "-296 -208 -272" "classname" "light" } { "classname" "func_plat" "model" "*2" } { "spawnflags" "2" "origin" "-192 -176 -80" "classname" "item_health" } { "light" "350" "origin" "-816 128 184" "classname" "light" } { "light" "350" "origin" "-664 -80 184" "classname" "light" } { "light" "250" "origin" "-656 112 32" "classname" "light" } { "origin" "-352 208 56" "classname" "light" "light" "250" } { "origin" "-184 504 24" "classname" "light" "light" "250" } { "classname" "item_armor1" "origin" "400 -888 0" } { "spawnflags" "1792" "classname" "item_armorInv" "origin" "-104 448 104" } { "classname" "item_armor2" "origin" "-680 496 32" } { "classname" "weapon_grenadelauncher" "origin" "168 1608 136" "spawnflags" "1792" } { "classname" "weapon_rocketlauncher" "origin" "1232 176 56" "spawnflags" "1792" } { "classname" "weapon_supernailgun" "origin" "-960 944 40" "spawnflags" "1792" } { "classname" "weapon_supershotgun" "origin" "752 1464 0" "spawnflags" "1792" } { "classname" "weapon_nailgun" "origin" "160 120 24" "spawnflags" "1792" } { "classname" "item_rockets" "origin" "-224 792 104" "spawnflags" "1792" } { "classname" "item_rockets" "origin" "-640 120 -56" "spawnflags" "1792" } { "light" "200" "origin" "-70 -1126 212" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "186 -1134 148" } { "light" "200" "origin" "138 -966 100" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "-150 -1318 260" } { "light" "150" "origin" "184 -880 72" "classname" "light" } { "style" "6" "light" "200" "origin" "-46 -1742 340" "classname" "light_torch_small_walltorch" } { "style" "1" "light" "200" "classname" "light_torch_small_walltorch" "origin" "-486 -1726 340" } { "origin" "-272 -1544 384" "classname" "light" "light" "200" } { "style" "6" "light" "200" "classname" "light_torch_small_walltorch" "origin" "-414 -2006 340" } { "style" "1" "light" "200" "origin" "-134 -1958 340" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "-472 -1840 328" "classname" "light" } { "classname" "light" "origin" "-72 -1592 328" "light" "150" } { "light" "150" "origin" "-320 -1424 264" "classname" "light" } { "light" "150" "origin" "-256 -1952 280" "classname" "light" } { "light" "200" "classname" "light" "origin" "-272 -1720 312" } { "origin" "-232 -1280 168" "classname" "path_corner" "targetname" "t5" "target" "t6" } { "classname" "path_corner" "origin" "-64 -1176 120" "targetname" "t6" "target" "t7" } { "origin" "152 -1104 56" "classname" "path_corner" "targetname" "t7" "target" "t8" } { "classname" "path_corner" "origin" "192 -952 8" "targetname" "t8" "target" "t9" } { "origin" "184 -808 8" "classname" "path_corner" "target" "t3" "targetname" "t9" } { "classname" "path_corner" "origin" "512 -776 8" "targetname" "t3" "target" "t10" } { "origin" "-200 -648 8" "classname" "path_corner" "targetname" "t4" "target" "t11" } { "classname" "monster_knight" "origin" "-360 -1616 232" "target" "t5" "angle" "90" } { "origin" "512 -648 8" "classname" "path_corner" "targetname" "t10" "target" "t4" } { "classname" "path_corner" "origin" "-200 -776 8" "targetname" "t11" "target" "t3" } { "classname" "monster_knight" "origin" "24 -632 24" "spawnflags" "256" "target" "t4" } { "classname" "monster_knight" "origin" "336 -752 24" "spawnflags" "256" "target" "t3" } { "classname" "monster_knight" "origin" "56 -712 24" "angle" "270" "spawnflags" "768" } { "spawnflags" "768" "angle" "270" "origin" "160 -712 24" "classname" "monster_knight" } { "classname" "monster_knight" "origin" "264 -712 24" "angle" "270" "spawnflags" "768" } { "classname" "item_health" "origin" "-432 -1640 208" "spawnflags" "1" } { "classname" "item_shells" "origin" "-352 -592 0" } { "classname" "func_door" "angle" "90" "spawnflags" "1" "targetname" "t13" "wait" "-1" "sounds" "3" "dmg" "100" "model" "*3" } { "health" "1" "angle" "90" "classname" "func_button" "target" "t12" "wait" "-1" "sounds" "1" "model" "*4" } { "classname" "func_button" "angle" "90" "health" "1" "target" "t12" "wait" "-1" "sounds" "1" "model" "*5" } { "classname" "trigger_counter" "targetname" "t12" "count" "2" "target" "t13" "model" "*6" } { "classname" "monster_demon1" "origin" "160 -128 24" "angle" "270" "targetname" "t12" } { "classname" "light" "origin" "-8 -288 64" "light" "200" } { "light" "200" "origin" "328 -288 64" "classname" "light" } { "light" "200" "origin" "-296 -448 -248" "classname" "light" } { "classname" "light" "origin" "160 -368 -248" "light" "200" } { "light" "200" "origin" "616 -448 -248" "classname" "light" } { "classname" "light" "origin" "408 -456 -248" "light" "200" } { "light" "200" "origin" "-40 -424 -248" "classname" "light" } { "classname" "light" "origin" "-280 -448 32" "light" "200" } { "light" "200" "origin" "632 -424 32" "classname" "light" } { "classname" "light" "origin" "160 -480 8" "light" "150" } { "classname" "func_door" "angle" "180" "targetname" "t12" "sounds" "3" "speed" "200" "wait" "-1" "lip" "-2" "model" "*7" } { "classname" "func_door" "angle" "0" "speed" "200" "wait" "-1" "lip" "-2" "model" "*8" } { "classname" "light" "origin" "160 -304 112" "light" "170" } { "classname" "light" "origin" "160 640 104" "light" "200" } { "classname" "func_door" "angle" "-1" "targetname" "t14" "sounds" "1" "model" "*9" } { "classname" "trigger_multiple" "target" "t14" "wait" "10" "model" "*10" } { "targetname" "t28" "classname" "func_door" "angle" "-1" "wait" "-1" "sounds" "1" "speed" "200" "spawnflags" "2048" "model" "*11" } { "angle" "270" "classname" "func_button" "target" "t15" "wait" "-1" "lip" "2" "sounds" "1" "spawnflags" "2048" "model" "*12" } { "classname" "light" "origin" "-296 432 0" "light" "200" } { "light" "200" "origin" "-312 416 152" "classname" "light" } { "classname" "light" "origin" "-184 320 146" "light" "200" } { "classname" "item_key2" "origin" "-552 192 -40" "sounds" "1" "spawnflags" "2048" } { "classname" "item_spikes" "origin" "-680 88 -48" } { "classname" "func_door" "angle" "-2" "spawnflags" "33" "speed" "10" "sounds" "3" "wait" "-1" "targetname" "t16" "dmg" "100" "model" "*13" "lip" "7" // svdijk -- added to prevent z-fighting } { "sounds" "3" "classname" "func_door" "angle" "90" "spawnflags" "2056" "wait" "-1" "model" "*14" } { "spawnflags" "2056" "angle" "270" "classname" "func_door" "wait" "-1" "model" "*15" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t16" "lip" "12" "model" "*16" } { "classname" "light" "origin" "888 1080 -104" "light" "160" } { "light" "160" "origin" "888 888 -104" "classname" "light" } { "classname" "light" "origin" "880 696 -104" "light" "160" } { "light" "160" "origin" "696 888 -104" "classname" "light" } { "classname" "light" "origin" "696 1080 -104" "light" "160" } { "light" "200" "origin" "696 672 -104" "classname" "light" } { "classname" "light" "origin" "568 512 -104" "light" "200" } { "light" "160" "origin" "840 504 -104" "classname" "light" } { "classname" "light" "origin" "832 328 -104" "light" "160" } { "classname" "light" "origin" "936 512 96" "light" "200" } { "classname" "light" "origin" "-248 1080 56" "light" "150" } { "classname" "light" "origin" "888 1264 176" "light" "170" } { "classname" "func_door" "angle" "-2" "targetname" "t17" "sounds" "1" "model" "*17" } { "classname" "trigger_multiple" "target" "t17" "wait" "5" "model" "*18" } { "classname" "light" "origin" "160 120 -24" "light" "160" } { "spawnflags" "256" "classname" "trigger_multiple" "target" "t18" "targetname" "t23" "model" "*19" } { "wait" "0.5" "classname" "trap_spikeshooter" "origin" "88 368 40" "angle" "0" "targetname" "t18" } { "classname" "func_wall" "spawnflags" "2048" "model" "*20" } { "classname" "monster_demon1" "origin" "-160 608 128" "targetname" "t19" } { "classname" "trigger_once" "target" "t19" "model" "*21" } { "classname" "light" "origin" "-528 512 -104" "light" "200" } { "light" "200" "origin" "-344 592 -104" "classname" "light" } { "classname" "light" "origin" "-336 760 -104" "light" "200" } { "light" "200" "origin" "-432 856 -104" "classname" "light" } { "classname" "monster_ogre" "origin" "-416 440 -40" "spawnflags" "1536" "target" "t20" } { "classname" "monster_shambler" "origin" "-272 296 -40" "spawnflags" "256" "target" "t20" } { "classname" "path_corner" "origin" "-328 272 -56" "targetname" "t20" "target" "t21" } { "origin" "-400 480 -56" "classname" "path_corner" "target" "t20" "targetname" "t21" } { "classname" "item_health" "origin" "-600 144 -64" } { "classname" "weapon_supershotgun" "origin" "440 512 0" "spawnflags" "2048" } { "classname" "light" "origin" "-120 176 184" "light" "250" } { "origin" "-96 0 184" "classname" "light" "light" "200" } { "classname" "light" "origin" "312 116 -48" "light" "200" } { "classname" "path_corner" "origin" "8 112 32" "target" "t25" "targetname" "t24" } { "origin" "312 112 32" "classname" "path_corner" "targetname" "t25" "target" "t24" } { "classname" "monster_ogre" "origin" "112 112 48" "target" "t24" "spawnflags" "256" } { "classname" "item_shells" "origin" "88 -160 0" "spawnflags" "1" } { "light" "250" "classname" "light" "origin" "-352 144 56" } { "classname" "monster_demon1" "origin" "-80 -440 -296" "spawnflags" "256" "target" "t26" } { "classname" "path_corner" "origin" "-216 -456 -312" "targetname" "t26" "target" "t27" } { "origin" "536 -448 -312" "classname" "path_corner" "target" "t26" "targetname" "t27" } { "light" "200" "origin" "320 232 -104" "classname" "light" } { "classname" "light" "origin" "312 0 -104" "light" "200" } { "light" "160" "origin" "-8 0 -104" "classname" "light" } { "classname" "light" "origin" "-8 232 -104" "light" "200" } { "light" "200" "origin" "-16 112 -104" "classname" "light" } { "classname" "light" "origin" "-248 -8 -104" "light" "200" } { "light" "200" "origin" "-472 120 -104" "classname" "light" } { "wait" "-1" "classname" "func_door" "angle" "-1" "targetname" "t15" "sounds" "1" "spawnflags" "2048" "model" "*22" } { "classname" "func_door" "angle" "-2" "spawnflags" "2081" "targetname" "t28" "wait" "10" "speed" "200" "sounds" "1" "model" "*23" } { "classname" "trigger_once" "target" "t28" "model" "*24" } { "classname" "trigger_once" "target" "t12" "model" "*25" } { "classname" "monster_ogre" "origin" "160 1432 128" "angle" "270" } { "classname" "monster_ogre" "origin" "-216 784 128" "angle" "90" } { "classname" "info_teleport_destination" "origin" "-360 888 24" "spawnflags" "2048" "targetname" "t1" } { "classname" "monster_zombie" "origin" "-288 -232 -296" "angle" "270" } { "classname" "monster_zombie" "origin" "168 -8 -104" "angle" "90" } { "classname" "monster_ogre" "origin" "648 1232 -64" "angle" "180" } { "sounds" "1" "classname" "func_door" "angle" "-2" "targetname" "t29" "model" "*26" } { "classname" "monster_ogre" "origin" "520 752 24" "angle" "90" "spawnflags" "256" "targetname" "t29" } { "classname" "trigger_once" "target" "t29" "model" "*27" } { "classname" "weapon_nailgun" "origin" "152 1608 136" "spawnflags" "2048" } { "classname" "path_corner" "origin" "544 896 8" "targetname" "t30" "target" "t31" } { "origin" "56 896 72" "classname" "path_corner" "target" "t30" "targetname" "t31" } { "classname" "path_corner" "origin" "168 552 8" "targetname" "t32" "target" "t33" } { "origin" "168 1392 8" "classname" "path_corner" "target" "t32" "targetname" "t33" } { "classname" "monster_knight" "origin" "240 584 24" "target" "t32" } { "classname" "monster_knight" "origin" "504 960 24" "target" "t30" "spawnflags" "256" } { "classname" "monster_knight" "origin" "-16 896 88" "angle" "0" } { "classname" "monster_knight" "origin" "256 1224 24" "angle" "225" "spawnflags" "256" } { "target" "t49" "origin" "-24 1064 16" "classname" "monster_ogre" } { "spawnflags" "256" "angle" "45" "origin" "-184 1080 128" "classname" "monster_ogre" } { "angle" "45" "origin" "-256 1216 128" "classname" "monster_knight" } { "targetname" "t16" "angle" "270" "origin" "784 520 56" "classname" "monster_demon1" } { "classname" "path_corner" "origin" "-352 888 16" "targetname" "t34" "target" "t35" } { "origin" "-120 888 8" "classname" "path_corner" "target" "t34" "targetname" "t35" } { "classname" "monster_ogre" "origin" "-184 912 24" "target" "t34" "spawnflags" "256" } { "classname" "monster_ogre" "origin" "-720 896 64" } { "classname" "monster_knight" "origin" "-344 760 24" "angle" "135" "spawnflags" "256" } { "classname" "monster_knight" "origin" "-392 584 24" "angle" "90" "spawnflags" "256" } { "angle" "90" "classname" "monster_knight" "origin" "-528 528 24" "spawnflags" "768" } { "targetname" "t37" "target" "t36" "origin" "-896 968 48" "classname" "path_corner" } { "target" "t37" "targetname" "t36" "classname" "path_corner" "origin" "-896 568 48" } { "spawnflags" "256" "target" "t36" "origin" "-840 600 24" "classname" "monster_ogre" } { "style" "32" "targetname" "t15" "light" "200" "origin" "-56 304 152" "classname" "light" } { "dmg" "100" "speed" "200" "targetname" "t15" "target" "t38" "classname" "func_train" "model" "*28" } { "target" "t39" "targetname" "t40" "origin" "-216 280 104" "classname" "path_corner" } { "target" "t40" "targetname" "t38" "classname" "path_corner" "origin" "-15 280 104" // svdijk -- changed to prevent z-fighting (was "-16 280 104") } { "target" "t38" "wait" "-1" "targetname" "t39" "origin" "-15 280 104" // svdijk -- changed to prevent z-fighting (was "-16 280 104") "classname" "path_corner" } { "angle" "180" "origin" "680 1472 24" "classname" "monster_ogre" "spawnflags" "256" } { "spawnflags" "256" "angle" "180" "origin" "864 1448 24" "classname" "monster_knight" } { "target" "t42" "targetname" "t41" "origin" "1024 1264 104" "classname" "path_corner" } { "targetname" "t42" "target" "t41" "classname" "path_corner" "origin" "704 1264 104" } { "target" "t41" "origin" "1056 1320 120" "classname" "monster_knight" } { "spawnflags" "257" "origin" "552 1280 128" "classname" "monster_knight" } { "spawnflags" "1" "origin" "432 1280 128" "classname" "monster_knight" } { "spawnflags" "2048" "angle" "0" "wait" "-1" "sounds" "0" "health" "1" "target" "t28" "classname" "func_button" "model" "*29" } { "origin" "-72 296 104" "classname" "item_health" } { "classname" "item_health" "origin" "-64 504 104" } { "origin" "-312 192 -64" "classname" "item_health" } { "spawnflags" "1" "origin" "-80 384 -64" "classname" "item_spikes" } { "origin" "-224 976 104" "classname" "item_shells" } { "target" "t666" "classname" "trigger_multiple" "wait" "10" "model" "*30" } { "target" "t45" "targetname" "t44" "origin" "984 568 8" "classname" "path_corner" } { "target" "t46" "targetname" "t45" "classname" "path_corner" "origin" "976 464 8" } { "target" "t47" "targetname" "t46" "origin" "1224 448 40" "classname" "path_corner" } { "target" "t44" "targetname" "t43" "classname" "path_corner" "origin" "1272 520 40" } { "target" "t48" "targetname" "t47" "classname" "path_corner" "origin" "1224 144 64" } { "targetname" "t48" "target" "t43" "origin" "1344 120 64" "classname" "path_corner" } { "target" "t45" "origin" "968 520 24" "classname" "monster_ogre" } { "spawnflags" "256" "target" "t43" "origin" "1312 328 80" "classname" "monster_knight" } { "spawnflags" "768" "target" "t47" "origin" "1240 296 80" "classname" "monster_ogre" } { "origin" "-360 1064 -8" "classname" "weapon_grenadelauncher" } { "target" "t50" "targetname" "t49" "origin" "-16 1168 0" "classname" "path_corner" } { "targetname" "t50" "target" "t49" "classname" "path_corner" "origin" "-232 1168 0" } { "origin" "1448 -128 -56" "classname" "light" } { "wait" "-1" "classname" "func_door" "angle" "270" "model" "*31" } { "wait" "-1" "targetname" "t52" "sounds" "3" "classname" "func_door" "angle" "90" "model" "*32" } { "classname" "light" "origin" "1984 -184 288" "light" "350" } { "classname" "light" "origin" "1760 -312 -184" "light" "200" } { "origin" "1832 -64 -184" "classname" "light" "light" "200" } { "light" "160" "origin" "1808 -296 -24" "classname" "light" } { "classname" "light" "origin" "1224 -8 -184" "light" "160" } { "light" "160" "origin" "1240 -208 -184" "classname" "light" } { "classname" "light" "origin" "1680 -104 -184" "light" "160" } { "light" "160" "origin" "1584 -304 -184" "classname" "light" } { "origin" "1592 -72 288" "classname" "light" } { "classname" "light" "origin" "1328 -232 288" } { "classname" "light" "origin" "1280 -16 327" "light" "250" } { "classname" "light" "origin" "1792 -152 88" "light" "160" } { "light" "160" "origin" "1632 -296 88" "classname" "light" } { "origin" "1696 -280 288" "classname" "light" } { "classname" "light" "origin" "1240 -224 -8" "light" "200" } { "classname" "func_wall" "spawnflags" "3072" "model" "*33" } { "classname" "func_wall" "spawnflags" "3072" "model" "*34" } { "classname" "func_wall" "spawnflags" "3072" "model" "*35" } { "classname" "func_wall" "spawnflags" "3072" "model" "*36" } { "classname" "func_wall" "spawnflags" "3072" "model" "*37" } { "classname" "monster_ogre" "origin" "1992 -192 200" "angle" "180" "spawnflags" "256" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "targetname" "t51" "model" "*38" } { "classname" "trigger_multiple" "target" "t51" "model" "*39" } { "classname" "func_plat" "model" "*40" } { "classname" "light" "origin" "1480 56 -168" "light" "160" } { "origin" "1432 280 -64" "classname" "light" "light" "160" } { "light" "160" "classname" "light" "origin" "1424 280 96" } { "light" "160" "origin" "1472 232 -168" "classname" "light" } { "classname" "monster_zombie" "origin" "1592 -24 160" "angle" "180" } { "classname" "monster_zombie" "origin" "1432 -304 112" "angle" "135" "spawnflags" "256" } { "classname" "monster_zombie" "origin" "1304 -288 112" "angle" "90" "spawnflags" "256" } { "classname" "monster_zombie" "origin" "1576 -216 136" "angle" "180" "spawnflags" "768" } { "classname" "monster_zombie" "origin" "1928 -80 200" "spawnflags" "768" "angle" "180" } { "angle" "180" "spawnflags" "768" "origin" "1928 -280 200" "classname" "monster_zombie" } { "classname" "trigger_changelevel" "map" "e2m3" "model" "*41" } { "classname" "light" "origin" "80 1544 40" "light" "160" } { "light" "160" "origin" "-112 1544 40" "classname" "light" } { "classname" "item_shells" "origin" "1056 552 8" } { "classname" "light" "origin" "-112 1672 40" "light" "160" } { "light" "160" "origin" "88 1680 40" "classname" "light" } { "classname" "item_health" "origin" "-168 1688 -8" "spawnflags" "1" } { "classname" "monster_knight" "origin" "-112 1616 16" "angle" "45" "spawnflags" "768" } { "classname" "monster_demon1" "origin" "1760 -208 -216" "angle" "180" } { "classname" "trigger_secret" "model" "*42" } { "classname" "trigger_secret" "model" "*43" } { "classname" "trigger_secret" "model" "*44" } { "classname" "trigger_multiple" "target" "t29" "model" "*45" } { "classname" "item_shells" "origin" "-144 -1728 288" "spawnflags" "768" } { "classname" "item_rockets" "origin" "2000 -304 176" "spawnflags" "1793" } { "classname" "item_rockets" "origin" "2000 -112 176" "spawnflags" "1793" } { "origin" "-62 -702 72" "classname" "ambient_swamp1" } { "classname" "ambient_swamp2" "origin" "386 -702 72" } { "origin" "-246 -470 -264" "classname" "ambient_swamp2" } { "classname" "ambient_swamp1" "origin" "554 -454 -264" } { "origin" "162 -430 -264" "classname" "ambient_swamp1" } { "spawnflags" "1" "origin" "-72 576 104" "classname" "item_shells" } { "spawnflags" "2048" "wait" "10" "target" "t16" "classname" "trigger_multiple" "model" "*46" } { "targetname" "t16" "sounds" "4" "wait" "-1" "angle" "-1" "classname" "func_door" "model" "*47" } { "origin" "-184 1480 168" "classname" "light" "light" "160" } { "classname" "light" "origin" "-224 1592 168" "light" "100" } { "target" "t52" "classname" "trigger_once" "model" "*48" } { "mangle" "20 30 0" "origin" "1224 -288 336" "classname" "info_intermission" } { "mangle" "20 180 0" "origin" "-352 760 240" "classname" "info_intermission" } { "mangle" "20 135 0" "origin" "480 -440 208" "classname" "info_intermission" } { "angle" "90" "origin" "-176 -1904 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-128 -1848 264" "angle" "90" } { "angle" "90" "origin" "-192 -1808 264" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "-320 -1824 264" "angle" "90" } { "spawnflags" "1792" "classname" "func_wall" "model" "*49" } { "spawnflags" "1792" "origin" "200 -664 0" "classname" "weapon_lightning" } { "origin" "-184 1512 144" "classname" "item_artifact_super_damage" } { "classname" "item_cells" "origin" "240 -664 0" "spawnflags" "1793" } { "classname" "item_cells" "origin" "392 640 0" "spawnflags" "1793" } { "classname" "item_cells" "origin" "-168 456 104" "spawnflags" "1793" } { "classname" "func_door" "angle" "-1" "spawnflags" "1" "wait" "6" "speed" "1000" "sounds" "3" "targetname" "t15" "model" "*50" } { "classname" "weapon_grenadelauncher" "origin" "1312 280 56" "spawnflags" "3584" } { "sounds" "2" "wait" "5" "message" "Shoot the buttons..." "spawnflags" "3584" "classname" "trigger_multiple" "targetname" "t53" "model" "*51" } { "classname" "trigger_relay" "origin" "-72 -320 48" "targetname" "t13" "killtarget" "t53" } { "classname" "worldspawn" "wad" "gfx/jr_med.wad" "worldtype" "0" "sounds" "9" "message" "the Crypt of Decay" } { "classname" "light" "origin" "192 -648 128" } { "classname" "info_player_start" "origin" "688 -1600 -312" "angle" "180" } { "classname" "light_flame_large_yellow" "origin" "650 -438 4" } { "origin" "386 -438 4" "classname" "light_flame_large_yellow" } { "origin" "66 -886 4" "classname" "light_flame_large_yellow" } { "origin" "322 -886 4" "classname" "light_flame_large_yellow" } { "light" "250" "origin" "192 -1408 288" "classname" "light" } { "light" "250" "classname" "light" "origin" "192 -1088 288" } { "light" "250" "origin" "112 -1248 272" "classname" "light" } { "light" "250" "classname" "light" "origin" "272 -1248 272" } { "light" "200" "origin" "192 -1056 32" "classname" "light" } { "light" "150" "origin" "192 -1248 24" "classname" "light" } { "origin" "194 -1462 108" "classname" "light_flame_large_yellow" } { "origin" "194 -1030 164" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "192 -1440 32" "classname" "light" } { "sounds" "2" "classname" "func_plat" "spawnflags" "1" "model" "*1" } { "origin" "226 -1670 -212" "classname" "light_flame_large_yellow" } { "light" "150" "origin" "88 -1552 -184" "classname" "light" } { "origin" "-22 -1374 -212" "classname" "light_flame_large_yellow" } { "light" "150" "origin" "328 -1256 -184" "classname" "light" } { "light" "150" "classname" "light" "origin" "56 -1256 -184" } { "classname" "light" "origin" "248 -1480 -184" "light" "150" } { "light" "250" "origin" "552 -1608 -72" "classname" "light" } { "light" "150" "origin" "432 -1656 -224" "classname" "light" } { "light" "150" "origin" "432 -1496 -224" "classname" "light" } { "light" "100" "origin" "192 -1248 -40" "classname" "light" } { "origin" "10 -438 4" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-254 -438 4" } { "light" "150" "origin" "192 -704 -136" "classname" "light" } { "light" "250" "origin" "192 -512 -136" "classname" "light" } { "classname" "light" "origin" "416 -512 -136" "light" "150" } { "light" "150" "origin" "-32 -512 -136" "classname" "light" } { "classname" "light" "origin" "-208 -512 -136" "light" "150" } { "light" "150" "origin" "592 -512 -136" "classname" "light" } { "classname" "light" "origin" "192 -840 -136" "light" "150" } { "light" "150" "origin" "-352 -672 -168" "classname" "light" } { "classname" "light" "origin" "-320 -832 -168" "light" "150" } { "light" "150" "origin" "-320 -512 -168" "classname" "light" } { "classname" "light" "origin" "696 -512 -168" "light" "150" } { "light" "150" "origin" "736 -672 -168" "classname" "light" } { "classname" "light" "origin" "704 -832 -168" "light" "150" } { "light" "150" "origin" "512 -864 -168" "classname" "light" } { "classname" "light" "origin" "-128 -864 -168" "light" "150" } { "light" "200" "origin" "-128 -320 8" "classname" "light" } { "classname" "light" "origin" "512 -320 8" "light" "200" } { "origin" "384 -24 32" "classname" "light" } { "classname" "light" "origin" "0 -24 32" } { "light" "200" "origin" "416 -192 -8" "classname" "light" } { "classname" "light" "origin" "-32 -192 -8" "light" "200" } { "light" "200" "origin" "840 48 72" "classname" "light" } { "light" "150" "origin" "576 -24 -56" "classname" "light" } { "light" "200" "origin" "624 -24 72" "classname" "light" } { "origin" "1002 354 -60" "classname" "light_flame_large_yellow" } { "light" "100" "origin" "1000 352 -128" "classname" "light" } { "classname" "light" "origin" "736 8 72" "light" "200" } { "light" "200" "origin" "936 88 72" "classname" "light" } { "light" "150" "origin" "688 -8 -32" "classname" "light" } { "classname" "light" "origin" "784 24 -104" "light" "150" } { "light" "150" "origin" "888 72 -32" "classname" "light" } { "light" "200" "origin" "872 208 -56" "classname" "light" } { "classname" "light" "origin" "872 400 -56" "light" "200" } { "light" "200" "origin" "872 592 -56" "classname" "light" } { "classname" "light" "origin" "744 568 88" "light" "150" } { "light" "150" "origin" "744 648 88" "classname" "light" } { "classname" "light" "origin" "704 608 -80" "light" "150" } { "origin" "866 730 -60" "classname" "light_flame_large_yellow" } { "classname" "light" "origin" "864 728 -128" "light" "100" } { "sounds" "3" "wait" "-1" "targetname" "t8" "spawnflags" "2049" "angle" "0" "classname" "func_door" "model" "*2" } { "spawnflags" "2048" "angle" "90" "target" "t8" "classname" "func_button" "wait" "-1" "model" "*3" } { "origin" "520 608 -64" "classname" "light" } { "light" "400" "origin" "192 608 -24" "classname" "light" } { "sounds" "1" "wait" "-1" "angle" "270" "spawnflags" "2058" "classname" "func_door_secret" "targetname" "t9" "model" "*4" } { "light" "150" "origin" "1064 640 -112" "classname" "light" } { "targetname" "t9" "angle" "180" "origin" "1024 640 -152" "classname" "monster_zombie" } { "targetname" "t9" "angle" "180" "origin" "1120 672 -152" "classname" "monster_zombie" } { "targetname" "t9" "angle" "180" "origin" "1088 600 -152" "classname" "monster_zombie" } { "origin" "976 336 -176" "classname" "item_health" } { "light" "150" "origin" "192 608 -104" "classname" "light" } { "origin" "192 288 -64" "classname" "light" } { "classname" "light_flame_large_yellow" "origin" "66 106 4" "light" "200" } { "light" "200" "origin" "-30 106 4" "classname" "light_flame_large_yellow" } { "classname" "light" "origin" "504 120 -248" "light" "200" } { "light" "200" "origin" "704 224 -248" "classname" "light" } { "classname" "light" "origin" "704 472 -248" "light" "200" } { "light" "200" "origin" "304 112 -248" "classname" "light" } { "classname" "light" "origin" "80 112 -248" "light" "200" } { "light" "200" "origin" "720 608 -248" "classname" "light" } { "spawnflags" "2048" "sounds" "1" "wait" "-1" "targetname" "t3" "classname" "func_door" "angle" "90" "model" "*5" } { "spawnflags" "2048" "wait" "-1" "angle" "270" "classname" "func_door" "message" "This door opens nearby..." "model" "*6" } { "spawnflags" "2048" "target" "t3" "wait" "-1" "classname" "func_button" "angle" "180" "model" "*7" } { "light" "250" "origin" "-448 184 0" "classname" "light" } { "light" "150" "origin" "-552 280 -224" "classname" "light" } { "classname" "light" "origin" "-392 280 -224" "light" "150" } { "light" "150" "origin" "-416 -32 104" "classname" "light" } { "classname" "light" "origin" "-320 -32 104" "light" "150" } { "light" "150" "origin" "-224 -32 104" "classname" "light" } { "light" "250" "origin" "-352 -32 -32" "classname" "light" } { "light" "200" "origin" "-1160 88 -248" "classname" "light" } { "light" "200" "origin" "-1048 88 -32" "classname" "light" } { "light" "200" "classname" "light" "origin" "-1160 224 -32" } { "origin" "-742 658 -44" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-926 658 -44" } { "light" "200" "origin" "-736 632 -96" "classname" "light" } { "classname" "light" "origin" "-928 632 -96" "light" "200" } { "light" "150" "origin" "-600 104 -248" "classname" "light" } { "classname" "light" "origin" "-696 424 -248" "light" "150" } { "light" "150" "origin" "-1152 408 -248" "classname" "light" } { "classname" "light" "origin" "-944 432 -248" "light" "150" } { "light" "150" "origin" "-856 64 -248" "classname" "light" } { "classname" "light" "origin" "-160 152 -248" "light" "150" } { "light" "150" "origin" "-160 448 -248" "classname" "light" } { "classname" "light" "origin" "-328 464 -248" "light" "150" } { "light" "150" "origin" "-256 176 -248" "classname" "light" } { "origin" "-574 410 -172" "classname" "light_flame_large_yellow" } { "classname" "light_flame_large_yellow" "origin" "-470 410 -172" } { "target" "t4" "classname" "trigger_teleport" "model" "*8" } { "light" "200" "style" "2" "origin" "-760 576 -216" "classname" "light" } { "targetname" "t4" "angle" "180" "origin" "120 -32 -112" "classname" "info_teleport_destination" } { "light" "200" "origin" "-264 384 112" "classname" "light" } { "classname" "light" "origin" "-264 288 112" "light" "200" } { "light" "200" "origin" "-264 192 112" "classname" "light" } { "classname" "light" "origin" "-264 480 112" "light" "200" } { "light" "250" "origin" "-264 304 -56" "classname" "light" } { "classname" "light" "origin" "-520 424 0" "light" "250" } { "light" "200" "origin" "-1120 608 72" "classname" "light" } { "classname" "light" "origin" "-1024 584 72" "light" "200" } { "light" "200" "origin" "-928 584 72" "classname" "light" } { "classname" "light" "origin" "-832 584 72" "light" "200" } { "light" "200" "origin" "-544 584 72" "classname" "light" } { "classname" "light" "origin" "-640 584 72" "light" "200" } { "light" "150" "origin" "-480 768 56" "classname" "light" } { "classname" "light" "origin" "-384 768 56" "light" "150" } { "classname" "light" "origin" "-712 120 -32" "light" "200" } { "sounds" "3" "wait" "-1" "targetname" "t5" "spawnflags" "2049" "angle" "180" "classname" "func_door" "model" "*9" } { "spawnflags" "2048" "angle" "270" "target" "t5" "wait" "-1" "classname" "func_button" "model" "*10" } { "style" "32" "targetname" "t5" "light" "200" "origin" "-352 552 -56" "classname" "light" } { "light" "150" "origin" "-432 768 -56" "classname" "light" } { "light" "150" "origin" "-520 680 -56" "classname" "light" } { "spawnflags" "2048" "sounds" "3" "targetname" "t5" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*11" } { "sounds" "3" "targetname" "t5" "spawnflags" "2049" "wait" "-1" "angle" "90" "classname" "func_door" "model" "*12" } { "origin" "-72 848 -56" "classname" "light" } { "origin" "-120 600 -8" "classname" "light" } { "classname" "light" "origin" "192 904 -8" } { "light" "200" "origin" "192 888 -248" "classname" "light" } { "classname" "light" "origin" "-104 600 -248" "light" "200" } { "light" "200" "origin" "376 984 -120" "classname" "light" } { "classname" "light" "origin" "504 760 -120" "light" "200" } { "light" "200" "origin" "-32 608 200" "classname" "light" } { "spawnflags" "2048" "sounds" "3" "wait" "-1" "angle" "-2" "classname" "func_door" "model" "*13" } { "origin" "-16 1456 16" "classname" "light" } { "light" "200" "origin" "384 1248 -56" "classname" "light" } { "classname" "light" "origin" "384 1440 -56" "light" "200" } { "light" "150" "origin" "256 1440 -56" "classname" "light" } { "classname" "light" "origin" "192 1248 -56" "light" "200" } { "light" "200" "origin" "384 1344 -88" "classname" "light" } { "classname" "light" "origin" "192 1152 -88" "light" "200" } { "classname" "light" "origin" "8 1456 -120" "light" "200" } { "spawnflags" "2048" "sounds" "1" "classname" "item_key2" "origin" "-16 1456 -152" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "model" "*14" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "model" "*15" } { "classname" "func_door" "angle" "-1" "targetname" "t6" "speed" "400" "wait" "-1" "sounds" "4" "spawnflags" "2048" "model" "*16" } { "classname" "trigger_once" "target" "t6" "model" "*17" } { "classname" "light" "origin" "-192 1456 -136" "light" "80" } { "classname" "light" "origin" "-16 1280 -136" "light" "80" } { "spawnflags" "768" "classname" "monster_hell_knight" "origin" "-16 1280 -168" "angle" "90" "targetname" "t6" } { "spawnflags" "256" "angle" "270" "origin" "-16 1632 -168" "classname" "monster_hell_knight" "targetname" "t6" } { "classname" "monster_hell_knight" "origin" "-192 1456 -168" "angle" "0" "targetname" "t6" } { "classname" "light" "origin" "152 1440 -56" "light" "150" } { "classname" "item_shells" "origin" "-104 1512 -192" "spawnflags" "1" } { "wait" "-1" "classname" "func_door" "angle" "0" "spawnflags" "2056" "model" "*18" } { "wait" "-1" "classname" "func_door" "angle" "180" "spawnflags" "2056" "model" "*19" } { "classname" "light" "origin" "-1120 832 -48" "light" "250" } { "classname" "light" "origin" "-1120 976 -24" "light" "250" } { "classname" "light" "origin" "-1240 1296 216" "light" "200" } { "light" "200" "origin" "-1240 1416 216" "classname" "light" } { "classname" "light" "origin" "-1240 1176 216" "light" "200" } { "classname" "light" "origin" "-712 1416 216" "light" "200" } { "light" "200" "origin" "-712 1296 216" "classname" "light" } { "classname" "light" "origin" "-712 1176 216" "light" "200" } { "light" "200" "origin" "-856 1296 216" "classname" "light" } { "classname" "light" "origin" "-1096 1296 216" "light" "200" } { "light" "200" "origin" "-976 1296 216" "classname" "light" } { "classname" "light_flame_small_white" "origin" "-1318 1514 -8" } { "origin" "-1318 1514 64" "classname" "light_flame_small_white" } { "classname" "light_flame_small_white" "origin" "-1318 1514 144" } { "origin" "-634 1078 -8" "classname" "light_flame_small_white" } { "classname" "light_flame_small_white" "origin" "-634 1078 64" } { "origin" "-634 1078 144" "classname" "light_flame_small_white" } { "classname" "func_plat" "spawnflags" "1" "model" "*20" } { "classname" "light" "origin" "-320 1536 184" "light" "250" } { "classname" "light" "origin" "-376 1312 120" "light" "250" } { "classname" "light" "origin" "-16 1536 184" "light" "200" } { "light" "200" "origin" "-560 1312 56" "classname" "light" } { "classname" "light" "origin" "24 1120 216" "light" "150" } { "classname" "light" "origin" "192 608 176" "light" "200" } { "wait" "-1" "classname" "func_door" "angle" "90" "spawnflags" "2049" "targetname" "t7" "sounds" "1" "model" "*21" } { "light" "150" "origin" "400 1104 224" "classname" "light" } { "light" "150" "origin" "-200 1056 224" "classname" "light" } { "light" "200" "origin" "192 960 224" "classname" "light" } { "light" "200" "origin" "192 784 224" "classname" "light" } { "classname" "light" "origin" "672 264 184" "light" "200" } { "light" "200" "origin" "384 184 184" "classname" "light" } { "classname" "light" "origin" "512 256 8" "light" "200" } { "classname" "light" "origin" "8 184 200" "light" "200" } { "classname" "light" "origin" "584 744 200" "light" "200" } { "classname" "light" "origin" "0 432 200" "light" "200" } { "classname" "trigger_once" "targetname" "t8" "target" "t9" "delay" "10" "model" "*22" } { "classname" "light" "origin" "192 -72 216" "light" "250" } { "classname" "light" "origin" "360 -168 360" "light" "200" } { "classname" "light" "origin" "296 -168 360" "light" "200" } { "origin" "472 -168 368" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "408 -168 360" } { "classname" "light" "origin" "384 -168 248" "light" "200" } { "classname" "light" "origin" "936 -304 328" "light" "200" } { "light" "200" "origin" "1000 -232 360" "classname" "light" } { "classname" "light" "origin" "864 -232 360" "light" "200" } { "light" "200" "origin" "864 -368 360" "classname" "light" } { "classname" "light" "origin" "1000 -368 360" "light" "200" } { "classname" "light" "origin" "736 -248 280" "light" "200" } { "light" "200" "origin" "552 -216 280" "classname" "light" } { "classname" "light" "origin" "16 144 -32" "light" "200" } { "classname" "light" "origin" "0 432 -136" "light" "200" } { "classname" "light" "origin" "192 384 184" "light" "200" } { "light" "200" "origin" "192 192 184" "classname" "light" } { "spawnflags" "2048" "classname" "func_button" "wait" "-1" "target" "t7" "model" "*23" } { "style" "33" "targetname" "t7" "classname" "light" "origin" "176 1152 200" "target" "t10" } { "classname" "info_null" "origin" "292 1152 180" "targetname" "t10" } { "classname" "light" "origin" "192 1224 200" "light" "150" } { "light" "150" "origin" "192 1376 200" "classname" "light" } { "classname" "light" "origin" "192 1536 200" "light" "200" } { "light" "150" "origin" "192 1080 200" "classname" "light" } { "classname" "weapon_nailgun" "origin" "184 -1520 -272" } { "classname" "func_button" "target" "t11" "angle" "-1" "targetname" "t12" "lip" "4" "wait" "0.1" "speed" "300" "health" "1" "model" "*24" } { "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t11" "wait" "10" "model" "*25" "lip" "7" // svdijk -- added to prevent z-fighting } { "classname" "func_door_secret" "angle" "90" "spawnflags" "8" "targetname" "t11" "model" "*26" "t_length" "65" // svdijk -- added to prevent z-fighting } { "classname" "light" "origin" "1248 -288 312" "light" "150" } { "light" "200" "origin" "1176 -400 352" "classname" "light" } { "classname" "item_health" "origin" "1336 -536 256" "spawnflags" "2" } { "classname" "light" "origin" "1320 -488 352" "light" "200" } { "classname" "trigger_multiple" "target" "t11" "wait" "10" "model" "*27" } { "classname" "item_armor1" "origin" "192 -592 -64" } { "classname" "item_shells" "origin" "176 592 -160" "spawnflags" "1" } { "classname" "weapon_nailgun" "origin" "-80 1456 -192" "spawnflags" "1792" } { "classname" "weapon_rocketlauncher" "origin" "56 1144 128" "spawnflags" "1792" } { "classname" "weapon_grenadelauncher" "origin" "-736 608 -280" "spawnflags" "1792" } { "classname" "item_spikes" "origin" "1120 -384 256" "spawnflags" "1" } { "classname" "item_rockets" "origin" "840 -432 192" "spawnflags" "1" } { "classname" "item_spikes" "origin" "-456 312 -80" } { "classname" "monster_zombie" "origin" "-1152 96 -88" "spawnflags" "256" "target" "t36" } { "origin" "-1120 32 -88" "classname" "monster_zombie" "spawnflags" "768" "target" "t36" } { "classname" "monster_zombie" "origin" "-1192 168 -88" "target" "t36" } { "classname" "monster_shambler" "origin" "-1120 1104 -56" "angle" "270" } { "classname" "monster_hell_knight" "origin" "-336 1312 8" "angle" "180" } { "classname" "monster_ogre" "origin" "-698 1446 -56" "angle" "270" "spawnflags" "256" } { "classname" "monster_hell_knight" "origin" "-888 1128 8" "angle" "90" "spawnflags" "256" } { "classname" "item_health" "origin" "-336 784 -128" } { "origin" "-408 608 -128" "classname" "item_health" } { "classname" "path_corner" "origin" "-1096 584 -120" "targetname" "t13" "target" "t14" } { "origin" "-496 584 -120" "classname" "path_corner" "targetname" "t14" "target" "t13" } { "classname" "monster_demon1" "origin" "-712 576 -104" "angle" "180" "target" "t13" } { "classname" "path_corner" "origin" "-528 472 -96" "targetname" "t15" "target" "t16" } { "origin" "-368 -32 -96" "classname" "path_corner" "target" "t15" "targetname" "t16" } { "classname" "monster_ogre" "origin" "-466 262 -56" "target" "t16" "spawnflags" "256" } { "target" "t22" "targetname" "t21" "origin" "56 -184 -120" "classname" "path_corner" } { "target" "t21" "targetname" "t20" "classname" "path_corner" "origin" "-128 -224 -120" } { "target" "t20" "targetname" "t19" "origin" "-128 -504 -56" "classname" "path_corner" } { "target" "t19" "targetname" "t18" "classname" "path_corner" "origin" "512 -504 -56" } { "target" "t18" "targetname" "t17" "origin" "512 -224 -120" "classname" "path_corner" } { "targetname" "t26" "target" "t17" "classname" "path_corner" "origin" "328 -184 -120" } { "target" "t23" "targetname" "t22" "classname" "path_corner" "origin" "-128 -200 -120" } { "target" "t24" "targetname" "t23" "classname" "path_corner" "origin" "-128 -552 -56" } { "target" "t25" "targetname" "t24" "origin" "512 -552 -56" "classname" "path_corner" } { "target" "t26" "targetname" "t25" "classname" "path_corner" "origin" "512 -200 -120" } { "spawnflags" "256" "target" "t21" "origin" "0 -184 -104" "classname" "monster_hell_knight" } { "spawnflags" "1" "origin" "376 -160 -104" "classname" "monster_hell_knight" } { "spawnflags" "768" "angle" "270" "origin" "190 -706 -40" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "90" "origin" "192 -1408 24" "classname" "monster_hell_knight" } { "origin" "40 -1424 0" "classname" "item_shells" "spawnflags" "1" } { "spawnflags" "1" "origin" "304 -1096 0" "classname" "item_health" } { "origin" "328 -1280 -272" "classname" "item_health" } { "origin" "40 -1256 -272" "classname" "item_spikes" } { "target" "t28" "targetname" "t27" "origin" "864 176 -168" "classname" "path_corner" } { "target" "t27" "targetname" "t28" "classname" "path_corner" "origin" "864 616 -168" } { "target" "t27" "origin" "862 446 -152" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "180" "origin" "526 -26 -104" "classname" "monster_ogre" } { "spawnflags" "256" "angle" "0" "origin" "-72 -24 -104" "classname" "monster_hell_knight" } { "spawnflags" "256" "origin" "-274 -34 -104" "classname" "monster_ogre" } { "spawnflags" "768" "angle" "270" "origin" "-512 760 -104" "classname" "monster_hell_knight" } { "spawnflags" "1793" "origin" "336 1104 128" "classname" "item_rockets" } { "angle" "45" "spawnflags" "256" "origin" "104 256 -136" "classname" "monster_zombie" } { "spawnflags" "769" "angle" "90" "origin" "192 488 -136" "classname" "monster_hell_knight" } { "wait" "1" "speed" "250" "lip" "16" "spawnflags" "5" "targetname" "t29" "dmg" "20" "angle" "180" "classname" "func_door" "model" "*28" } { "wait" "1" "targetname" "t29" "speed" "250" "dmg" "20" "lip" "16" "spawnflags" "5" "classname" "func_door" "sounds" "1" "model" "*29" } { "wait" "2" "target" "t29" "classname" "trigger_multiple" "model" "*30" } { "origin" "506 1762 -124" "classname" "light_torch_small_walltorch" "style" "1" } { "classname" "light_torch_small_walltorch" "origin" "274 2010 -124" } { "light" "200" "origin" "152 1824 -40" "classname" "light" } { "classname" "light" "origin" "288 1824 -40" "light" "200" } { "light" "200" "origin" "288 1696 -40" "classname" "light" } { "classname" "light" "origin" "152 1704 -40" "light" "200" } { "light" "220" "origin" "0 1704 -40" "classname" "light" } { "angle" "180" "classname" "func_door_secret" "targetname" "t35" "spawnflags" "16" "sounds" "1" "model" "*31" } { "spawnflags" "2" "origin" "-16 1816 -192" "classname" "item_health" } { "origin" "432 1672 -320" "classname" "light" "light" "220" } { "spawnflags" "1792" "origin" "-16 1752 -192" "classname" "item_rockets" } { "angle" "270" "origin" "-192 1580 168" "classname" "trap_spikeshooter" "targetname" "t32" } { "spawnflags" "256" "classname" "trap_spikeshooter" "origin" "236 1536 168" "angle" "180" "targetname" "t32" } { "classname" "trap_spikeshooter" "origin" "0 1580 168" "angle" "270" "targetname" "t32" } { "angle" "90" "origin" "-96 1492 168" "classname" "trap_spikeshooter" "targetname" "t32" } { "classname" "trap_spikeshooter" "origin" "148 1376 168" "angle" "0" "targetname" "t33" } { "angle" "180" "origin" "236 1256 168" "classname" "trap_spikeshooter" "targetname" "t33" } { "spawnflags" "256" "classname" "trap_spikeshooter" "origin" "192 1580 168" "angle" "270" "targetname" "t33" } { "spawnflags" "257" "angle" "90" "origin" "192 -16 153" "classname" "monster_hell_knight" } { "spawnflags" "257" "angle" "180" "origin" "864 -248 217" "classname" "monster_shambler" } { "angle" "180" "origin" "464 -184 185" "classname" "monster_hell_knight" } { "classname" "monster_hell_knight" "origin" "192 -176 153" "angle" "90" "spawnflags" "1" "target" "t31" } { "spawnflags" "769" "angle" "90" "origin" "190 1166 153" "classname" "monster_ogre" } { "spawnflags" "2048" "origin" "48 1456 -192" "classname" "weapon_grenadelauncher" } { "spawnflags" "1" "origin" "-96 1376 -192" "classname" "item_rockets" } { "angle" "270" "spawnflags" "768" "classname" "monster_ogre" "origin" "862 662 -152" } { "light" "120" "origin" "192 -352 -264" "classname" "light" } { "spawnflags" "768" "origin" "326 -1490 -248" "classname" "monster_ogre" "angle" "180" "target" "t42" } { "origin" "192 552 128" "classname" "item_health" } { "spawnflags" "1024" "classname" "item_health" "origin" "176 672 128" } { "spawnflags" "1025" "origin" "184 1312 128" "classname" "item_health" } { "classname" "item_health" "origin" "-16 1480 128" "spawnflags" "1025" } { "origin" "672 -328 176" "classname" "item_health" } { "classname" "item_health" "origin" "776 -192 176" } { "origin" "784 312 -176" "classname" "item_shells" } { "spawnflags" "256" "angle" "315" "origin" "-26 1094 152" "classname" "monster_ogre" } { "classname" "monster_ogre" "origin" "406 1094 152" "angle" "225" "spawnflags" "768" } { "spawnflags" "1" "origin" "-200 1128 128" "classname" "item_rockets" } { "origin" "-550 -478 212" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "-550 -166 212" } { "origin" "-214 -326 252" "classname" "light_torch_small_walltorch" } { "light" "150" "origin" "-120 -176 192" "classname" "light" } { "classname" "light" "origin" "56 -176 192" "light" "150" } { "origin" "-816 1488 -80" "classname" "item_health" } { "classname" "item_health" "origin" "-752 1488 -80" } { "spawnflags" "1536" "origin" "-688 1488 -80" "classname" "item_health" } { "spawnflags" "1" "origin" "176 1264 -160" "classname" "item_shells" } { "classname" "func_door" "angle" "270" "targetname" "t31" "wait" "-1" "spawnflags" "2048" "model" "*32" } { "wait" "-1" "sounds" "1" "speed" "300" "classname" "func_door" "angle" "90" "model" "*33" } { "speed" "300" "classname" "func_door" "angle" "270" "wait" "-1" "model" "*34" } { "classname" "item_health" "origin" "400 1464 -160" "spawnflags" "1024" } { "classname" "item_health" "origin" "-1136 528 -128" } { "classname" "monster_ogre" "origin" "-370 -218 88" "targetname" "t31" "spawnflags" "1" } { "classname" "monster_hell_knight" "origin" "-64 -176 152" "angle" "0" "spawnflags" "768" "targetname" "t31" } { "classname" "item_health" "origin" "-488 -480 64" } { "classname" "light" "origin" "680 -1600 -160" } { "classname" "item_spikes" "origin" "984 -192 192" "spawnflags" "1" } { "classname" "monster_ogre" "origin" "-490 -410 88" "angle" "45" } { "classname" "trigger_multiple" "target" "t32" "wait" "1" "spawnflags" "1024" "targetname" "t44" "model" "*35" } { "classname" "trigger_multiple" "target" "t33" "wait" "1" "spawnflags" "1024" "model" "*36" } { "classname" "item_rockets" "origin" "-96 272 -384" } { "classname" "weapon_supernailgun" "origin" "-1200 208 -112" "spawnflags" "1792" } { "classname" "func_door_secret" "spawnflags" "2051" "targetname" "t36" "angle" "90" "model" "*37" "t_length" "65" // svdijk -- added to prevent z-fighting } { "classname" "light" "origin" "-1288 640 -80" "light" "160" } { "light" "160" "origin" "-1288 128 -80" "classname" "light" } { "classname" "light" "origin" "-1288 264 -80" "light" "160" } { "light" "160" "origin" "-1288 392 -80" "classname" "light" } { "classname" "light" "origin" "-1288 520 -80" "light" "160" } { "classname" "func_door_secret" "targetname" "t36" "angle" "270" "spawnflags" "2049" "model" "*38" "t_length" "65" // svdijk -- added to prevent z-fighting } { "classname" "item_armor2" "origin" "1128 600 -176" "spawnflags" "1024" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "11" "targetname" "t34" "model" "*39" } { "classname" "light_torch_small_walltorch" "origin" "-246 -1310 -204" "light" "250" } { "classname" "trigger_once" "target" "t34" "model" "*40" } { "classname" "item_spikes" "origin" "-240 -1288 -312" "spawnflags" "1" } { "spawnflags" "1" "origin" "-240 -1368 -312" "classname" "item_spikes" } { "sounds" "3" "classname" "func_door" "angle" "-2" "spawnflags" "3585" "wait" "90" "targetname" "t6" "model" "*41" } { "sounds" "3" "classname" "func_door" "targetname" "t6" "spawnflags" "3585" "angle" "-2" "wait" "90" "model" "*42" } { "sounds" "3" "classname" "func_door" "angle" "0" "spawnflags" "1537" "targetname" "t6" "wait" "90" "model" "*43" } { "classname" "light_torch_small_walltorch" "origin" "-42 1642 -108" "light" "200" } { "classname" "item_health" "origin" "-72 560 -384" } { "origin" "-152 560 -384" "classname" "item_health" } { "targetname" "t31" "spawnflags" "513" "angle" "90" "origin" "848 -376 216" "classname" "monster_hell_knight" } { "targetname" "t31" "spawnflags" "768" "origin" "-512 -248 88" "classname" "monster_shambler" } { "spawnflags" "768" "angle" "180" "origin" "382 1246 -136" "classname" "monster_ogre" } { "spawnflags" "768" "classname" "monster_ogre" "origin" "190 1438 -136" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "640 -1664 -312" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "-400 -240 88" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "-216 1088 152" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "-512 792 -104" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "888 624 -152" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "-96 1456 -168" "angle" "0" } { "spawnflags" "2048" "classname" "func_wall" "model" "*44" } { "spawnflags" "2048" "classname" "func_wall" "model" "*45" } { "classname" "func_plat" "height" "192" "sounds" "2" "model" "*46" } { "classname" "item_health" "origin" "-1184 72 -352" } { "classname" "light" "origin" "-952 1408 80" "light" "200" } { "classname" "light" "origin" "-1120 1176 48" "light" "250" } { "classname" "light" "origin" "-104 288 -344" "light" "200" } { "classname" "light" "origin" "-512 376 -304" "light" "200" } { "classname" "trigger_multiple" "target" "t35" "model" "*47" } { "classname" "light" "origin" "192 -376 -16" "light" "150" } { "classname" "light" "origin" "192 -328 176" "light" "150" } { "classname" "trigger_multiple" "target" "t32" "spawnflags" "768" "wait" "0.5" "model" "*48" } { "classname" "trigger_multiple" "spawnflags" "768" "wait" "0.5" "target" "t33" "targetname" "t44" "model" "*49" } { "origin" "-1176 112 -112" "classname" "item_rockets" } { "origin" "-736 544 -280" "classname" "item_armorInv" } { "classname" "func_button" "angle" "180" "target" "t36" "model" "*50" } { "classname" "info_null" "origin" "-1332 1116 -36" "targetname" "t37" } { "classname" "light" "origin" "-1296 1120 -32" "target" "t37" "angle" "60" } { "spawnflags" "2048" "classname" "func_wall" "model" "*51" } { "spawnflags" "2048" "classname" "func_wall" "model" "*52" } { "classname" "light" "origin" "192 -152 -344" "light" "160" } { "classname" "light" "origin" "192 32 -344" "light" "160" } { "classname" "light" "origin" "32 168 -344" "light" "140" } { "light" "160" "origin" "-16 408 -344" "classname" "light" } { "classname" "light" "origin" "192 368 -344" "light" "140" } { "light" "140" "origin" "448 368 -344" "classname" "light" } { "classname" "light" "origin" "528 592 -344" "light" "200" } { "light" "200" "origin" "408 808 -344" "classname" "light" } { "classname" "light" "origin" "192 832 -344" "light" "200" } { "light" "200" "origin" "-40 728 -344" "classname" "light" } { "classname" "light" "origin" "-168 632 -344" "light" "200" } { "light" "200" "origin" "-160 976 -344" "classname" "light" } { "classname" "light" "origin" "592 456 -344" "light" "200" } { "classname" "light" "origin" "192 352 -232" "light" "200" } { "light" "200" "origin" "32 264 -232" "classname" "light" } { "classname" "light" "origin" "-184 432 -336" "light" "160" } { "light" "160" "origin" "-192 144 -336" "classname" "light" } { "classname" "light" "origin" "-776 280 -312" "light" "200" } { "light" "200" "origin" "-864 432 -312" "classname" "light" } { "classname" "light" "origin" "-1096 432 -312" "light" "200" } { "light" "200" "origin" "-1168 272 -312" "classname" "light" } { "classname" "light" "origin" "-944 64 -312" "light" "200" } { "light" "200" "origin" "-664 136 -312" "classname" "light" } { "light" "200" "origin" "-1112 592 -96" "classname" "light" } { "classname" "light" "origin" "-1040 1256 -32" "light" "150" } { "light" "200" "origin" "-880 1128 80" "classname" "light" } { "classname" "light" "origin" "-712 1400 -16" "light" "200" } { "classname" "light" "origin" "104 -600 -224" "light" "200" } { "light" "200" "origin" "280 -600 -224" "classname" "light" } { "classname" "trigger_changelevel" "map" "e2m4" "model" "*53" } { "light" "160" "origin" "-312 808 -72" "classname" "light" } { "light" "200" "origin" "192 1776 -312" "classname" "light" } { "classname" "light" "origin" "-392 568 -56" "light" "160" } { "classname" "light" "origin" "-1224 1504 8" "light" "170" } { "light" "170" "origin" "-1304 1392 8" "classname" "light" } { "classname" "light" "origin" "-640 1168 -8" "light" "170" } { "light" "160" "origin" "352 -1248 56" "classname" "light" } { "classname" "light" "origin" "40 -1248 56" "light" "160" } { "light" "160" "origin" "192 -1216 -176" "classname" "light" } { "classname" "light" "origin" "24 -1376 -232" "light" "160" } { "light" "160" "origin" "224 -1624 -232" "classname" "light" } { "classname" "light" "origin" "368 -1392 -232" "light" "160" } { "classname" "light" "origin" "8 -464 -40" "light" "140" } { "light" "140" "origin" "384 -464 -40" "classname" "light" } { "classname" "light" "origin" "-544 800 -56" "light" "140" } { "classname" "trigger_secret" "model" "*54" } { "classname" "trigger_secret" "model" "*55" } { "light" "200" "origin" "760 1856 -40" "classname" "light" } { "classname" "light" "origin" "760 1664 -40" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "538 1762 -124" "style" "1" "light" "200" } { "style" "1" "classname" "light_torch_small_walltorch" "origin" "850 1930 -124" "light" "200" } { "origin" "850 1618 -124" "classname" "light_torch_small_walltorch" "style" "1" "light" "200" } { "classname" "light" "origin" "912 1856 -40" "light" "200" } { "light" "200" "origin" "912 1664 -40" "classname" "light" } { "light" "200" "origin" "1064 1776 -172" "classname" "light" } { "light" "200" "origin" "1080 1856 -40" "classname" "light" } { "classname" "light" "origin" "1080 1664 -40" "light" "200" } { "classname" "light" "origin" "1176 1776 -172" "light" "200" } { "light" "170" "origin" "672 1768 -296" "classname" "light" } { "target" "t38" "classname" "trigger_teleport" "model" "*56" } { "targetname" "t38" "origin" "1144 1776 -88" "classname" "info_teleport_destination" } { "map" "e2m7" "classname" "trigger_changelevel" "model" "*57" } { "light" "160" "origin" "840 1768 -200" "classname" "light" } { "light" "140" "origin" "408 608 -344" "classname" "light" } { "classname" "item_spikes" "origin" "-16 240 -160" "spawnflags" "2048" } { "classname" "weapon_supernailgun" "origin" "-1256 1448 -80" } { "origin" "432 1160 152" "classname" "item_artifact_super_damage" } { "message" "The portal lies beyond..." "targetname" "t40" "wait" "-1" "speed" "20" "sounds" "4" "angle" "-2" "classname" "func_door" "model" "*58" } { "origin" "432 1672 -368" "classname" "item_armor2" } { "target" "t39" "sounds" "1" "wait" "-1" "classname" "func_button" "model" "*59" } { "message" "The underwater barrier is lowered..." "target" "t40" "targetname" "t39" "spawnflags" "1" "classname" "trigger_once" "model" "*60" } { "classname" "trigger_secret" "model" "*61" } { "light" "200" "origin" "-128 -704 -224" "classname" "light" } { "classname" "light" "origin" "512 -704 -224" "light" "200" } { "light" "200" "origin" "192 -832 -224" "classname" "light" } { "mangle" "20 240 0" "origin" "400 1048 240" "classname" "info_intermission" } { "mangle" "20 145 0" "origin" "-160 144 64" "classname" "info_intermission" } { "mangle" "-20 45 0" "origin" "-320 -824 -144" "classname" "info_intermission" } { "classname" "func_wall" "spawnflags" "1792" "model" "*62" } { "classname" "item_artifact_super_damage" "origin" "928 1768 -240" "spawnflags" "1792" } { "classname" "light" "origin" "8 1800 -120" "light" "220" } { "classname" "weapon_lightning" "origin" "1216 1784 -264" "spawnflags" "1792" } { "classname" "item_cells" "origin" "880 1648 -264" "spawnflags" "1793" } { "spawnflags" "1793" "origin" "880 1864 -264" "classname" "item_cells" } { "spawnflags" "1792" "classname" "func_wall" "model" "*63" } { "spawnflags" "1792" "classname" "func_wall" "model" "*64" } { "spawnflags" "1792" "classname" "func_wall" "model" "*65" } { "classname" "info_player_coop" "origin" "664 -1520 -312" "angle" "180" } { "angle" "180" "origin" "592 -1600 -312" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "680 -1712 -312" "angle" "180" } { "classname" "air_bubbles" "origin" "720 1384 -320" } { "classname" "light" "origin" "680 1376 -312" } { "classname" "func_door_secret" "angle" "180" "spawnflags" "2" "targetname" "t41" "model" "*66" "t_length" "65" // svdijk -- added to prevent z-fighting } { "classname" "trigger_multiple" "target" "t41" "model" "*67" } { "origin" "688 1176 -312" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "480 1408 -312" } { "origin" "448 1552 -312" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "840 1080 -312" } { "origin" "840 1080 -160" "classname" "light" "light" "200" } { "light" "200" "classname" "light" "origin" "840 1080 0" } { "classname" "light" "origin" "840 1080 232" "light" "200" } { "classname" "item_artifact_envirosuit" "origin" "576 1440 -344" } { "classname" "item_artifact_invulnerability" "origin" "544 1248 -344" } { "light" "200" "origin" "840 936 232" "classname" "light" } { "classname" "light" "origin" "840 760 232" "light" "150" } { "light" "120" "origin" "808 600 232" "classname" "light" } { "classname" "item_health" "origin" "824 960 152" } { "origin" "848 880 152" "classname" "item_health" } { "classname" "item_health" "origin" "808 768 152" } { "classname" "trigger_multiple" "message" "Welcome to the Well of Wishes!" "wait" "5" "sounds" "1" "model" "*68" } { "classname" "trigger_multiple" "sounds" "1" "wait" "3" "message" "The Dopefish Lives!" "model" "*69" } { "classname" "func_wall" "spawnflags" "1792" "model" "*70" } { "classname" "trigger_secret" "model" "*71" } { "spawnflags" "1" "origin" "-1312 1392 -80" "classname" "item_spikes" } { "classname" "func_wall" "spawnflags" "1792" "model" "*72" } { "classname" "light" "origin" "-544 600 -248" "light" "200" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "194 -214 196" "spawnflags" "2048" } { "light" "200" "origin" "352 984 -328" "classname" "light" } { "classname" "light" "origin" "96 976 -328" "light" "200" } { "classname" "light" "origin" "640 776 -336" "light" "200" } { "classname" "func_plat" "spawnflags" "1" "model" "*73" } { "classname" "monster_fish" "origin" "656 352 -336" "spawnflags" "256" } { "spawnflags" "256" "origin" "432 424 -336" "classname" "monster_fish" } { "classname" "monster_fish" "origin" "296 968 -336" "spawnflags" "256" } { "origin" "-48 800 -336" "classname" "monster_fish" } { "classname" "monster_fish" "origin" "-896 248 -312" } { "origin" "-744 328 -312" "classname" "monster_fish" } { "classname" "path_corner" "origin" "272 -1504 -264" "targetname" "t42" "target" "t43" } { "origin" "56 -1352 -264" "classname" "path_corner" "target" "t42" "targetname" "t43" } { "classname" "item_health" "origin" "312 -1336 -272" } { "origin" "544 -1488 -336" "classname" "item_health" } { "classname" "item_health" "origin" "312 1464 -160" } { "origin" "56 1488 -192" "classname" "item_health" } { "classname" "trigger_once" "killtarget" "t44" "spawnflags" "3072" "model" "*74" } { "classname" "item_rockets" "origin" "216 648 120" "spawnflags" "1" } { "classname" "item_shells" "origin" "136 648 120" "spawnflags" "1" } { "wad" "gfx/tim.wad" "classname" "worldspawn" "sounds" "7" "worldtype" "0" "message" "the Underearth" } { "angle" "90" "origin" "1136 -1100 -72" "classname" "info_player_start" } { "origin" "1184 -776 -152" "classname" "light" "light" "150" } { "classname" "light" "origin" "1704 -584 -184" "light" "150" } { "classname" "light" "origin" "1640 -688 -184" "light" "150" } { "classname" "light" "origin" "1696 -888 -192" "light" "150" } { "classname" "light" "origin" "1088 -960 -152" "light" "150" } { "classname" "light" "origin" "1248 -960 -152" "light" "150" } { "classname" "light" "origin" "1016 -768 -152" "light" "100" } { "classname" "light" "origin" "896 -920 -152" "light" "150" } { "light" "100" "origin" "1584 -208 -112" "classname" "light" } { "light" "100" "origin" "1776 -208 -112" "classname" "light" } { "light" "150" "origin" "1584 -88 -112" "classname" "light" } { "origin" "1774 58 -76" "classname" "light_torch_small_walltorch" } { "light" "100" "origin" "1584 -488 -232" "classname" "light" } { "light" "100" "origin" "1768 -480 -232" "classname" "light" } { "light" "150" "origin" "1752 -112 -176" "classname" "light" } { "light" "150" "origin" "1592 -120 -176" "classname" "light" } { "light" "150" "origin" "1592 -248 -192" "classname" "light" } { "light" "200" "origin" "1768 -240 -192" "classname" "light" } { "light" "150" "origin" "1676 -220 -188" "classname" "light" } { "light" "150" "origin" "1672 -40 -136" "classname" "light" } { "light" "150" "origin" "1676 -376 -252" "classname" "light" } { "light" "250" "origin" "1112 952 -92" "classname" "light" } { "light" "200" "origin" "1280 928 -152" "classname" "light" } { "classname" "light" "origin" "704 952 -92" "light" "250" } { "classname" "light" "origin" "824 1112 -92" "light" "200" } { "classname" "light" "origin" "952 760 -92" "light" "200" } { "classname" "light" "origin" "824 760 -92" "light" "200" } { "light" "250" "origin" "952 1112 -92" "classname" "light" } { "classname" "light" "origin" "1128 -848 288" "light" "500" } { "classname" "light" "origin" "1144 -432 288" } { "classname" "light" "origin" "864 -552 272" "light" "200" } { "classname" "light" "origin" "1392 -568 168" "light" "200" } { "classname" "light" "origin" "1416 -592 -24" "light" "150" } { "classname" "light" "origin" "888 -584 -24" "light" "150" } { "classname" "light_torch_small_walltorch" "origin" "1058 -466 -24" "light" "225" } { "origin" "1214 -466 -24" "classname" "light_torch_small_walltorch" "light" "225" } { "classname" "light_torch_small_walltorch" "origin" "1198 -66 40" "light" "300" } { "classname" "light" "origin" "1144 -204 172" "light" "150" } { "classname" "light" "origin" "1144 -292 -32" "light" "150" } { "classname" "item_spikes" "origin" "880 -592 -96" "spawnflags" "1" } { "classname" "item_health" "origin" "1068 -944 -96" } { "classname" "light" "origin" "1128 -1084 96" "light" "300" } { "classname" "light" "origin" "888 -848 248" "light" "150" } { "light" "150" "origin" "1504 -896 248" "classname" "light" } { "classname" "light" "origin" "1304 -1048 24" "light" "225" } { "classname" "light" "origin" "1520 -872 -192" "light" "150" } { "light" "100" "origin" "1384 -776 -184" "classname" "light" } { "classname" "light" "origin" "1368 -912 -184" "light" "100" } { "classname" "light" "origin" "1584 496 148" "light" "200" } { "light" "200" "origin" "1488 496 148" "classname" "light" } { "classname" "light" "origin" "1688 164 148" "light" "200" } { "light" "200" "origin" "1352 496 148" "classname" "light" } { "classname" "light" "origin" "1608 496 -36" "light" "200" } { "light" "200" "origin" "1456 496 -36" "classname" "light" } { "classname" "light" "origin" "1692 600 -12" "light" "200" } { "light" "200" "origin" "1274 618 -64" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1274 378 -64" "light" "200" } { "classname" "light" "origin" "1256 496 -40" "light" "200" } { "spawnflags" "2056" "wait" "-1" "classname" "func_door" "angle" "270" "model" "*1" } { "wait" "-1" "spawnflags" "2056" "sounds" "3" "angle" "90" "classname" "func_door" "model" "*2" } { "light" "200" "origin" "1968 1792 -257" "classname" "light" } { "light" "250" "origin" "1880 1792 -105" "classname" "light" } { "classname" "light" "origin" "1976 1944 56" "light" "150" } { "light" "150" "origin" "1992 1624 64" "classname" "light" } { "classname" "light" "origin" "1944 1736 64" "light" "150" } { "light" "150" "origin" "1944 1832 64" "classname" "light" } { "classname" "light" "origin" "1128 496 -24" "light" "250" } { "light" "150" "origin" "1120 632 -24" "classname" "light" } { "light" "200" "origin" "928 544 -24" "classname" "light" } { "classname" "light" "origin" "640 664 -8" "light" "200" } { "light" "200" "origin" "848 672 -8" "classname" "light" } { "classname" "light" "origin" "1024 544 -188" "light" "175" } { "light" "250" "origin" "64 192 136" "classname" "light" } { "classname" "light" "origin" "528 184 136" "light" "250" } { "light" "200" "origin" "72 408 8" "classname" "light" } { "classname" "light" "origin" "80 -48 8" "light" "200" } { "light" "250" "origin" "400 384 80" "classname" "light" } { "classname" "light" "origin" "392 -16 80" "light" "250" } { "classname" "light" "origin" "312 184 -80" "light" "200" } { "light" "200" "origin" "440 184 -80" "classname" "light" } { "classname" "light" "origin" "504 368 -120" "light" "250" } { "light" "150" "origin" "632 192 -120" "classname" "light" } { "classname" "light" "origin" "504 -16 -120" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "774 446 -172" "light" "250" } { "origin" "774 -70 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "light" "250" "origin" "896 -128 152" "classname" "light" } { "classname" "light" "origin" "896 184 152" "light" "250" } { "light" "150" "origin" "656 184 216" "classname" "light" } { "classname" "light" "origin" "304 368 -152" "light" "200" } { "light" "200" "origin" "0 480 -168" "classname" "light" } { "classname" "light" "origin" "96 376 -168" "light" "200" } { "classname" "light" "origin" "16 1480 -96" "light" "200" } { "light" "200" "origin" "1280 1824 -120" "classname" "light" } { "light" "200" "origin" "504 1816 -120" "classname" "light" } { "classname" "light" "origin" "712 1808 -120" "light" "200" } { "light" "200" "origin" "1064 1808 -120" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "858 1950 -172" "light" "250" } { "origin" "658 1950 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "classname" "light_torch_small_walltorch" "origin" "666 1682 -172" "light" "250" } { "origin" "858 1682 -172" "classname" "light_torch_small_walltorch" "light" "250" } { "classname" "light" "origin" "1248 1384 -32" "light" "200" } { "classname" "light" "origin" "1688 936 -136" "light" "200" } { "light" "250" "origin" "1856 1444 -52" "classname" "light" } { "light" "150" "origin" "1864 1316 -192" "classname" "light" } { "classname" "light" "origin" "1776 1212 -192" "light" "150" } { "light" "150" "origin" "1696 1076 -192" "classname" "light" } { "classname" "light_torch_small_walltorch" "origin" "1770 730 -64" "light" "250" } { "classname" "light" "origin" "1760 1720 -201" "light" "250" } { "classname" "light" "origin" "1632 1520 -201" "light" "200" } { "classname" "light" "origin" "1984 1504 -201" "light" "200" } { "light" "250" "classname" "light_torch_small_walltorch" "origin" "1874 2104 -300" } { "light" "250" "origin" "1712 2104 -300" "classname" "light_torch_small_walltorch" } { "light" "200" "classname" "light" "origin" "1792 2048 48" } { "classname" "light_flame_large_yellow" "origin" "1362 1778 0" } { "classname" "light" "origin" "1408 1776 -124" "light" "200" } { "classname" "light" "origin" "1520 1880 -84" "light" "175" } { "light" "175" "origin" "1416 1512 -84" "classname" "light" } { "classname" "light" "origin" "1376 1568 -164" "light" "150" } { "light" "150" "origin" "1416 1888 -164" "classname" "light" } { "classname" "light" "origin" "1544 2072 -164" "light" "150" } { "classname" "light" "origin" "1552 1968 36" "light" "250" } { "classname" "light" "origin" "1416 1968 -16" "light" "175" } { "light" "175" "origin" "1416 2176 -16" "classname" "light" } { "classname" "light" "origin" "1240 2176 -16" "light" "175" } { "light" "175" "origin" "1240 2000 -16" "classname" "light" } { "classname" "light" "origin" "1264 1576 -72" "light" "200" } { "light" "200" "origin" "992 1480 -40" "classname" "light" } { "light" "200" "classname" "light_torch_small_walltorch" "origin" "968 1632 -132" } { "light" "200" "origin" "968 1328 -132" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1474 2234 -133" "light" "200" } { "origin" "1182 2234 -133" "classname" "light_torch_small_walltorch" "light" "200" } { "classname" "light" "origin" "1936 1480 48" "light" "150" } { "light" "150" "origin" "1544 1528 64" "classname" "light" } { "classname" "light" "origin" "1472 1488 24" "light" "150" } { "classname" "light" "origin" "1400 1664 96" "light" "150" } { "light" "200" "origin" "1792 2176 -221" "classname" "light" } { "classname" "light" "origin" "1880 2288 -221" "light" "200" } { "light" "200" "origin" "2048 2288 -221" "classname" "light" } { "classname" "light" "origin" "2128 2208 -221" "light" "200" } { "light" "200" "origin" "2160 1992 -205" "classname" "light" } { "origin" "2288 1952 -29" "classname" "light" } { "light" "250" "origin" "2274 1738 -172" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "2274 1682 -172" "light" "250" } { "light" "200" "origin" "2376 2184 -152" "classname" "light" } { "light" "200" "origin" "2618 1658 -169" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "2618 1368 -169" "light" "200" } { "light" "200" "origin" "2176 1488 -169" "classname" "light_torch_small_walltorch" } { "light" "200" "origin" "2298 626 24" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "1930 738 24" "light" "200" } { "light" "200" "origin" "2050 394 24" "classname" "light_torch_small_walltorch" } { "classname" "func_plat" "model" "*3" } { "light" "150" "origin" "2152 1784 -312" "classname" "light" } { "classname" "light" "origin" "2232 936 -4" "light" "200" } { "classname" "light" "origin" "2232 1040 48" } { "classname" "light_torch_small_walltorch" "origin" "2034 1034 -164" "light" "200" } { "classname" "light" "origin" "2304 1040 280" "light" "200" } { "light" "200" "origin" "2168 1040 280" "classname" "light" } { "origin" "2130 2452 -112" "classname" "light_flame_large_yellow" "light" "250" } { "classname" "light_flame_large_yellow" "origin" "1858 2452 -112" "light" "250" } { "classname" "light" "origin" "2132 2416 -188" "light" "150" } { "light" "150" "origin" "1860 2416 -188" "classname" "light" } { "light" "200" "origin" "2256 1968 -453" "classname" "light" } { "classname" "light" "origin" "2256 2184 -453" "light" "200" } { "light" "200" "origin" "2216 2384 -453" "classname" "light" } { "classname" "light" "origin" "1792 2400 -453" "light" "200" } { "light" "175" "origin" "1984 2400 -453" "classname" "light" } { "light" "150" "origin" "2168 1608 -9" "classname" "light" } { "classname" "light" "origin" "2368 1600 -9" "light" "150" } { "light" "150" "origin" "2240 1424 44" "classname" "light" } { "classname" "light" "origin" "2400 1424 44" "light" "150" } { "light" "150" "origin" "2560 1424 44" "classname" "light" } { "classname" "light" "origin" "2560 1560 44" "light" "175" } { "light" "150" "origin" "2232 1288 44" "classname" "light" } { "light" "175" "origin" "2384 1424 -160" "classname" "light" } { "classname" "light" "origin" "2232 1288 -160" "light" "175" } { "light" "150" "origin" "2164 932 -172" "classname" "light" } { "classname" "light" "origin" "2308 932 -172" "light" "150" } { "light" "150" "origin" "2232 776 24" "classname" "light" } { "classname" "light" "origin" "2192 664 24" "light" "150" } { "light" "150" "origin" "2016 696 24" "classname" "light" } { "classname" "light" "origin" "1912 496 24" "light" "150" } { "light" "175" "origin" "80 1616 -120" "classname" "light" } { "classname" "light" "origin" "72 1888 -120" "light" "175" } { "light" "175" "origin" "296 1616 -120" "classname" "light" } { "light" "175" "origin" "304 1888 -120" "classname" "light" } { "targetname" "t20" "angle" "90" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t21" "angle" "120" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t22" "angle" "150" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t19" "angle" "60" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t18" "angle" "30" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t17" "angle" "0" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t24" "angle" "210" "classname" "trap_spikeshooter" "origin" "192 1752 -208" "spawnflags" "1" } { "targetname" "t23" "angle" "180" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t25" "angle" "240" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t26" "angle" "270" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t27" "angle" "300" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "targetname" "t28" "angle" "330" "spawnflags" "1" "origin" "192 1752 -208" "classname" "trap_spikeshooter" } { "delay" ".1" "targetname" "t29" "target" "t17" "classname" "trigger_multiple" "model" "*4" } { "delay" ".1" "targetname" "t17" "target" "t18" "classname" "trigger_multiple" "model" "*5" } { "delay" ".1" "targetname" "t18" "target" "t19" "classname" "trigger_multiple" "model" "*6" } { "delay" ".1" "targetname" "t19" "target" "t20" "classname" "trigger_multiple" "model" "*7" } { "delay" ".1" "targetname" "t20" "target" "t21" "classname" "trigger_multiple" "model" "*8" } { "delay" ".1" "targetname" "t21" "target" "t22" "classname" "trigger_multiple" "model" "*9" } { "delay" ".1" "targetname" "t22" "target" "t23" "classname" "trigger_multiple" "model" "*10" } { "delay" ".1" "targetname" "t23" "target" "t24" "classname" "trigger_multiple" "model" "*11" } { "delay" ".1" "targetname" "t24" "target" "t25" "classname" "trigger_multiple" "model" "*12" } { "delay" ".1" "targetname" "t25" "target" "t26" "classname" "trigger_multiple" "model" "*13" } { "delay" ".1" "targetname" "t26" "target" "t27" "classname" "trigger_multiple" "model" "*14" } { "delay" ".1" "targetname" "t27" "target" "t28" "classname" "trigger_multiple" "model" "*15" } { "target" "t29" "wait" "1.3" "classname" "trigger_multiple" "model" "*16" } { "origin" "192 1750 -188" "classname" "light_flame_large_yellow" } { "light" "125" "origin" "214 1752 -166" "classname" "light" } { "classname" "light" "origin" "192 1774 -166" "light" "125" } { "light" "125" "origin" "170 1750 -166" "classname" "light" } { "classname" "light" "origin" "194 1726 -166" "light" "125" } { "target" "t31" "wait" "-1" "angle" "0" "classname" "func_button" "model" "*17" } { "target" "t31" "angle" "180" "wait" "-1" "classname" "func_button" "model" "*18" } { "target" "t31" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*19" } { "target" "t31" "angle" "90" "wait" "-1" "classname" "func_button" "model" "*20" } { "wait" "-1" "targetname" "t30" "sounds" "4" "speed" "50" "angle" "-1" "classname" "func_door" "model" "*21" } { "count" "4" "targetname" "t31" "target" "t30" "classname" "trigger_counter" "model" "*22" } { "light" "150" "origin" "2424 1080 -176" "classname" "light" } { "classname" "light" "origin" "2424 992 -176" "light" "150" } { "targetname" "t40" "angle" "180" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "160" } { "targetname" "t40" "angle" "140" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "120" } { "targetname" "t40" "angle" "200" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t40" "classname" "trap_spikeshooter" "origin" "2434 1036 -192" "spawnflags" "1" "angle" "220" } { "targetname" "t40" "angle" "240" "spawnflags" "1" "origin" "2434 1036 -192" "classname" "trap_spikeshooter" } { "targetname" "t41" "target" "t40" "wait" ".5" "classname" "trigger_multiple" "model" "*23" } { "target" "t41" "classname" "trigger_multiple" "model" "*24" } { "target" "t41" "classname" "trigger_multiple" "model" "*25" } { "target" "t41" "classname" "trigger_multiple" "model" "*26" } { "target" "t41" "classname" "trigger_multiple" "model" "*27" } { "target" "t41" "classname" "trigger_multiple" "model" "*28" } { "target" "t41" "classname" "trigger_multiple" "model" "*29" } { "target" "t41" "classname" "trigger_multiple" "model" "*30" } { "light" "125" "origin" "2196 1200 -204" "classname" "light" } { "classname" "light" "origin" "2284 1200 -204" "light" "125" } { "light" "125" "origin" "2284 1112 -204" "classname" "light" } { "classname" "light" "origin" "2388 1104 -204" "light" "125" } { "light" "125" "origin" "2284 1000 -204" "classname" "light" } { "classname" "light" "origin" "2140 1008 -204" "light" "125" } { "light" "125" "origin" "2132 1096 -204" "classname" "light" } { "classname" "light" "origin" "2132 1160 -204" "light" "125" } { "light" "200" "origin" "528 1816 -392" "classname" "light" } { "classname" "light" "origin" "736 1808 -392" "light" "200" } { "light" "200" "origin" "1040 1808 -392" "classname" "light" } { "classname" "light" "origin" "744 1424 -392" "light" "200" } { "light" "200" "origin" "752 1288 -416" "classname" "light" } { "light" "200" "origin" "760 1064 -376" "classname" "light" } { "classname" "func_train" "spawnflags" "33" "targetname" "t42" "dmg" "1000" "sounds" "1" "target" "t124" "speed" "250" "model" "*31" } { "classname" "func_door" "angle" "-2" "wait" "-1" "targetname" "t43" "speed" "50" "sounds" "3" "model" "*32" } { "classname" "func_button" "angle" "-2" "wait" "-1" "target" "t42" "sounds" "1" "model" "*33" } { "classname" "trigger_once" "target" "t43" "targetname" "t42" "delay" "2" "model" "*34" } { "classname" "light" "origin" "1936 1784 -288" "light" "125" } { "classname" "monster_ogre" "origin" "1976 1784 -328" "angle" "180" } { "classname" "func_door" "angle" "90" "wait" "-1" "sounds" "1" "model" "*35" } { "classname" "func_door" "angle" "270" "targetname" "t44" "wait" "-1" "model" "*36" } { "classname" "light" "origin" "64 264 8" "light" "125" } { "light" "125" "origin" "64 120 8" "classname" "light" } { "classname" "light" "origin" "64 192 8" "light" "100" } { "classname" "trigger_once" "target" "t44" "model" "*37" } { "classname" "light" "origin" "512 184 -8" "light" "175" } { "targetname" "t119" "classname" "func_door" "angle" "90" "wait" "-1" "speed" "40" "model" "*38" } { "targetname" "t119" "classname" "func_door" "wait" "-1" "angle" "270" "speed" "40" "sounds" "4" "model" "*39" } { "targetname" "t119" "classname" "func_door" "wait" "-1" "angle" "-1" "speed" "30" "message" "Go for a swim first..." "sounds" "3" "model" "*40" "origin" "-1 0 0" // svdijk -- added to prevent z-fighting } { "classname" "func_button" "angle" "0" "wait" "-1" "target" "t45" "model" "*41" } { "classname" "light" "origin" "36 184 84" "light" "75" } { "classname" "light" "origin" "752 184 -192" "light" "150" } { "classname" "light" "origin" "544 536 -152" "light" "125" } { "classname" "func_door" "angle" "-2" "sounds" "1" "wait" "-1" "targetname" "t45" "model" "*42" } { "wait" "-1" "sounds" "1" "angle" "-2" "classname" "func_door" "targetname" "t45" "model" "*43" } { "light" "125" "origin" "544 -152 -152" "classname" "light" } { "classname" "item_artifact_envirosuit" "origin" "1024 492 -232" } { "classname" "item_armor1" "origin" "2128 1752 -352" } { "classname" "light_flame_small_yellow" "origin" "1024 368 -4" "light" "250" } { "classname" "light" "origin" "1024 400 -64" "light" "150" } { "wait" "5" "sounds" "1" "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t51" "model" "*44" } { "wait" "5" "sounds" "1" "classname" "func_door" "angle" "-2" "spawnflags" "1" "targetname" "t51" "model" "*45" } { "sounds" "3" "classname" "func_button" "angle" "270" "wait" "3" "target" "t51" "model" "*46" } { "classname" "light" "origin" "1224 712 -216" "light" "100" } { "classname" "light" "origin" "1232 768 -192" "light" "100" } { "light" "75" "origin" "1168 760 -232" "classname" "light" } { "light" "100" "origin" "1232 800 -208" "classname" "light" } { "sounds" "1" "origin" "1860 472 -8" "classname" "item_key2" "spawnflags" "2048" } { "classname" "light" "origin" "1112 1568 -40" "light" "200" } { "light" "150" "origin" "-96 1440 -160" "classname" "light" } { "classname" "light" "origin" "384 1440 -160" "light" "150" } { "light" "200" "origin" "248 1408 -96" "classname" "light" } { "light" "150" "origin" "968 1480 -128" "classname" "light" } { "light" "150" "origin" "1008 -592 -32" "classname" "light" } { "classname" "light" "origin" "1264 -592 -32" "light" "150" } { "light" "200" "origin" "880 -840 -56" "classname" "light" } { "classname" "light" "origin" "1376 -856 -56" "light" "200" } { "light" "175" "origin" "264 184 -8" "classname" "light" } { "light" "175" "origin" "1464 -864 -208" "classname" "light" } { "light" "175" "origin" "1816 160 -56" "classname" "light" } { "classname" "light" "origin" "1560 160 -56" "light" "175" } { "light" "175" "origin" "1544 1632 104" "classname" "light" } { "classname" "light" "origin" "1792 1624 128" "light" "175" } { "classname" "item_health" "origin" "1068 -980 -104" } { "spawnflags" "1" "classname" "item_shells" "origin" "1344 -1160 -96" } { "classname" "monster_ogre" "origin" "1008 -128 40" "angle" "315" "targetname" "t59" "spawnflags" "1" } { "classname" "trigger_once" "target" "t59" "model" "*47" } { "classname" "monster_ogre" "origin" "896 96 56" "angle" "270" "target" "t60" "spawnflags" "1" } { "classname" "path_corner" "origin" "896 208 40" "target" "t60" "targetname" "t61" } { "origin" "896 -16 40" "classname" "path_corner" "targetname" "t60" "target" "t61" } { "classname" "path_corner" "origin" "168 392 -56" "target" "t62" "targetname" "t63" } { "origin" "168 -16 -56" "classname" "path_corner" "targetname" "t62" "target" "t63" } { "classname" "path_corner" "origin" "88 344 -56" "targetname" "t64" "target" "t65" "spawnflags" "256" } { "origin" "88 72 -56" "classname" "path_corner" "target" "t64" "targetname" "t65" "spawnflags" "256" } { "classname" "monster_hell_knight" "origin" "88 224 -40" "angle" "90" "target" "t64" "spawnflags" "257" } { "classname" "monster_hell_knight" "origin" "168 232 -40" "angle" "270" "target" "t62" "spawnflags" "1" } { "classname" "monster_zombie" "origin" "544 -120 -208" "angle" "90" "targetname" "t45" } { "classname" "monster_zombie" "origin" "544 496 -208" "angle" "270" "targetname" "t45" } { "classname" "monster_wizard" "origin" "664 428 216" "angle" "225" "spawnflags" "1" } { "angle" "135" "origin" "664 -56 216" "classname" "monster_wizard" "spawnflags" "257" } { "classname" "light" "origin" "1736 88 -40" "light" "100" } { "classname" "monster_ogre" "origin" "904 -120 56" "angle" "0" "targetname" "t66" "spawnflags" "1281" } { "classname" "trigger_once" "target" "t66" "spawnflags" "256" "model" "*48" } { "classname" "item_health" "origin" "1168 -408 -80" "spawnflags" "1" } { "classname" "item_health" "origin" "1168 -104 -16" } { "classname" "item_spikes" "origin" "928 216 32" } { "classname" "item_rockets" "origin" "632 -48 32" } { "classname" "item_health" "origin" "32 392 -64" } { "light" "200" "origin" "1688 288 148" "classname" "light" } { "classname" "light" "origin" "1688 464 148" "light" "200" } { "classname" "light_torch_small_walltorch" "origin" "1814 622 -64" "light" "250" } { "classname" "light" "origin" "1768 344 -72" "light" "200" } { "classname" "trigger_monsterjump" "angle" "0" "model" "*49" } { "targetname" "t100" "classname" "monster_ogre" "origin" "1504 272 24" "angle" "0" "spawnflags" "256" } { "targetname" "t68" "target" "t67" "origin" "1352 576 -120" "classname" "path_corner" "spawnflags" "256" } { "target" "t68" "targetname" "t67" "classname" "path_corner" "origin" "1352 416 -120" "spawnflags" "256" } { "target" "t68" "angle" "90" "origin" "1360 480 -104" "classname" "monster_demon1" "spawnflags" "257" } { "targetname" "t70" "target" "t69" "origin" "1472 496 -120" "classname" "path_corner" } { "target" "t70" "targetname" "t69" "classname" "path_corner" "origin" "1688 496 -120" } { "target" "t69" "angle" "270" "origin" "1648 544 -104" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t71" "targetname" "t72" "origin" "1984 688 -24" "classname" "path_corner" "spawnflags" "256" } { "target" "t72" "targetname" "t71" "classname" "path_corner" "origin" "1984 448 -24" "spawnflags" "256" } { "target" "t71" "angle" "270" "origin" "1992 536 -8" "classname" "monster_ogre" "spawnflags" "257" } { "target" "t74" "targetname" "t73" "origin" "2120 680 -24" "classname" "path_corner" } { "targetname" "t74" "target" "t73" "classname" "path_corner" "origin" "2240 680 -24" } { "target" "t74" "angle" "225" "origin" "2256 736 -8" "classname" "monster_ogre" "spawnflags" "1" } { "targetname" "t78" "angle" "90" "origin" "2232 1312 -8" "classname" "monster_ogre" "spawnflags" "256" } { "target" "t76" "angle" "90" "origin" "2232 1008 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "targetname" "t76" "target" "t75" "origin" "2120 968 -216" "classname" "path_corner" } { "target" "t76" "targetname" "t75" "classname" "path_corner" "origin" "2336 968 -216" } { "classname" "light" "origin" "2384 2400 -152" "light" "200" } { "targetname" "t77" "wait" "-1" "sounds" "1" "speed" "300" "angle" "-2" "classname" "func_door" "model" "*50" } { "targetname" "t77" "angle" "180" "origin" "2512 2312 -200" "classname" "monster_demon1" "spawnflags" "256" } { "targetname" "t77" "classname" "monster_demon1" "origin" "2512 2160 -200" "angle" "180" } { "classname" "item_health" "origin" "2504 2200 -224" } { "light" "150" "origin" "2536 2312 -128" "classname" "light" } { "classname" "light" "origin" "2536 2160 -128" "light" "150" } { "target" "t77" "classname" "trigger_once" "model" "*51" } { "spawnflags" "2" "origin" "2368 2336 -224" "classname" "item_health" } { "spawnflags" "1" "origin" "2504 2240 -224" "classname" "item_spikes" } { "origin" "2408 2072 -224" "classname" "item_shells" } { "target" "t78" "classname" "trigger_once" "model" "*52" } { "targetname" "t78" "angle" "90" "origin" "2240 1272 -200" "classname" "monster_demon1" } { "light" "150" "origin" "1120 1384 -40" "classname" "light" } { "light" "200" "origin" "1200 1248 -104" "classname" "light" } { "light" "250" "origin" "1288 1032 -4" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "1256 1032 -64" "classname" "light" } { "classname" "light_flame_small_yellow" "origin" "568 1032 -4" "light" "250" } { "classname" "light" "origin" "600 1032 -64" "light" "150" } { "light" "250" "origin" "888 1272 -4" "classname" "light_flame_small_yellow" } { "light" "150" "origin" "888 1240 -64" "classname" "light" } { "light" "200" "origin" "608 1232 -108" "classname" "light" } { "target" "t79" "wait" "-1" "angle" "180" "classname" "func_button" "model" "*53" } { "targetname" "t79" "message" "This door is opened near by..." "sounds" "3" "speed" "35" "angle" "-1" "wait" "-1" "classname" "func_door" "model" "*54" } { "light" "100" "origin" "580 1208 -148" "classname" "light" } { "light" "200" "origin" "1224 736 -8" "classname" "light" } { "target" "t80" "classname" "trigger_once" "model" "*55" } { "targetname" "t80" "angle" "315" "origin" "640 1088 128" "classname" "monster_wizard" } { "targetname" "t80" "classname" "monster_wizard" "origin" "616 720 128" "angle" "0" } { "targetname" "t80" "angle" "180" "origin" "1280 680 128" "classname" "monster_wizard" "spawnflags" "256" } { "target" "t82" "origin" "1248 1080 24" "classname" "monster_wizard" "spawnflags" "1" } { "targetname" "t82" "target" "t81" "origin" "1168 1064 8" "classname" "path_corner" } { "target" "t82" "targetname" "t81" "classname" "path_corner" "origin" "720 1064 8" } { "targetname" "t80" "classname" "monster_wizard" "origin" "584 1112 128" "angle" "315" "spawnflags" "256" } { "origin" "1256 944 -184" "classname" "item_health" } { "spawnflags" "1" "origin" "1116 584 -256" "classname" "item_spikes" } { "targetname" "t79" "angle" "315" "origin" "1000 1464 -168" "classname" "monster_ogre" } { "target" "t85" "targetname" "t86" "origin" "1456 1824 -192" "classname" "path_corner" "spawnflags" "256" } { "target" "t86" "targetname" "t85" "classname" "path_corner" "origin" "1456 1560 -192" "spawnflags" "256" } { "target" "t85" "angle" "270" "origin" "1456 1664 -176" "classname" "monster_ogre" "spawnflags" "256" } { "targetname" "t91" "angle" "270" "origin" "1560 1944 -320" "classname" "monster_zombie" "spawnflags" "256" } { "targetname" "t91" "classname" "monster_zombie" "origin" "1600 1912 -320" "angle" "270" } { "angle" "225" "origin" "1960 1984 -320" "classname" "monster_zombie" } { "targetname" "t91" "classname" "monster_zombie" "origin" "1904 1928 -320" "angle" "225" } { "targetname" "t91" "angle" "270" "origin" "1624 1768 -320" "classname" "monster_zombie" } { "target" "t87" "classname" "monster_zombie" "origin" "1696 1912 -320" "angle" "0" } { "target" "t89" "angle" "270" "origin" "1704 1800 -320" "classname" "monster_zombie" } { "target" "t87" "targetname" "t88" "origin" "1648 1912 -336" "classname" "path_corner" } { "target" "t88" "targetname" "t87" "classname" "path_corner" "origin" "1848 1904 -336" } { "targetname" "t90" "target" "t89" "origin" "1648 1824 -336" "classname" "path_corner" } { "target" "t90" "targetname" "t89" "classname" "path_corner" "origin" "1768 1752 -336" } { "target" "t91" "classname" "trigger_once" "model" "*56" } { "spawnflags" "1" "origin" "1496 1808 -200" "classname" "item_health" } { "spawnflags" "1" "origin" "1184 2176 -192" "classname" "item_health" } { "classname" "item_health" "origin" "1184 2128 -192" "spawnflags" "1" } { "spawnflags" "1" "origin" "1264 1680 -192" "classname" "item_health" } { "target" "t92" "targetname" "t93" "origin" "2376 2304 -216" "classname" "path_corner" } { "target" "t93" "targetname" "t92" "classname" "path_corner" "origin" "2376 1984 -216" } { "target" "t95" "targetname" "t94" "origin" "2144 1608 -216" "classname" "path_corner" } { "target" "t94" "targetname" "t95" "classname" "path_corner" "origin" "2376 1608 -216" } { "target" "t92" "angle" "270" "origin" "2376 2176 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "135" "origin" "2416 1760 -200" "classname" "monster_hell_knight" "spawnflags" "257" } { "target" "t94" "angle" "180" "origin" "2320 1608 -200" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "90" "origin" "2152 1840 -200" "classname" "monster_ogre" "spawnflags" "257" } { "target" "t97" "targetname" "t96" "origin" "2096 2376 -216" "classname" "path_corner" "spawnflags" "256" } { "target" "t96" "targetname" "t97" "classname" "path_corner" "origin" "2232 2208 -216" "spawnflags" "256" } { "target" "t96" "angle" "135" "origin" "2200 2264 -200" "classname" "monster_wizard" "spawnflags" "257" } { "origin" "2104 1544 -224" "classname" "item_shells" } { "origin" "2176 1240 -32" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "2256 1240 -32" } { "origin" "1928 584 -32" "classname" "item_shells" } { "spawnflags" "1" "origin" "2040 1072 -32" "classname" "item_health" } { "classname" "item_health" "origin" "2040 1024 -32" "spawnflags" "1" } { "angle" "225" "origin" "2352 1160 -200" "classname" "monster_hell_knight" "spawnflags" "256" } { "angle" "180" "origin" "1864 1192 -216" "classname" "monster_zombie" } { "classname" "monster_zombie" "origin" "1776 1192 -216" "angle" "180" } { "target" "t99" "targetname" "t98" "origin" "1688 1192 -232" "classname" "path_corner" } { "target" "t98" "targetname" "t99" "classname" "path_corner" "origin" "1688 1048 -232" } { "target" "t98" "angle" "90" "origin" "1688 1112 -216" "classname" "monster_zombie" } { "origin" "536 416 32" "classname" "item_shells" } { "target" "t100" "classname" "trigger_once" "spawnflags" "256" "model" "*57" } { "origin" "1784 408 -128" "classname" "item_health" } { "classname" "item_health" "origin" "1784 448 -128" } { "origin" "1736 728 -128" "classname" "item_rockets" } { "target" "t101" "sounds" "1" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*58" } { "light" "250" "origin" "1418 234 52" "classname" "light_torch_small_walltorch" } { "targetname" "t101" "classname" "trigger_secret" "model" "*59" } { "targetname" "t102" "angle" "180" "classname" "trigger_monsterjump" "model" "*60" } { "target" "t102" "killtarget" "t102" "classname" "trigger_once" "model" "*61" } { "origin" "1568 1968 -352" "classname" "item_health" } { "classname" "item_health" "origin" "1608 1968 -352" } { "origin" "2112 1776 -352" "classname" "item_shells" "spawnflags" "2048" } { "origin" "1920 2232 -352" "classname" "item_spikes" } { "classname" "item_spikes" "origin" "2008 2232 -352" } { "classname" "item_shells" "origin" "2176 1440 -224" } { "target" "t66" "classname" "trigger_once" "model" "*62" } { "origin" "1744 0 -128" "classname" "item_spikes" "spawnflags" "1" } { "target" "t103" "targetname" "t104" "origin" "-56 1432 -224" "classname" "path_corner" "spawnflags" "256" } { "target" "t104" "targetname" "t103" "classname" "path_corner" "origin" "312 1432 -224" "spawnflags" "256" } { "target" "t103" "origin" "40 1440 -208" "classname" "monster_ogre" "spawnflags" "257" } { "angle" "45" "origin" "56 1616 -208" "classname" "monster_hell_knight" "spawnflags" "1" } { "target" "t105" "targetname" "t106" "origin" "520 1816 -232" "classname" "path_corner" } { "target" "t106" "targetname" "t105" "classname" "path_corner" "origin" "920 1816 -232" } { "target" "t105" "origin" "624 1800 -216" "classname" "monster_hell_knight" "spawnflags" "1" } { "angle" "0" "origin" "480 1824 64" "classname" "monster_wizard" "spawnflags" "257" } { "targetname" "t107" "classname" "monster_wizard" "origin" "656 1816 64" "angle" "0" "spawnflags" "1" } { "targetname" "t107" "angle" "0" "origin" "840 1816 64" "classname" "monster_wizard" "spawnflags" "257" } { "target" "t107" "classname" "trigger_once" "model" "*63" } { "origin" "1440 2200 -192" "classname" "item_shells" } { "classname" "item_shells" "origin" "1440 2160 -192" } { "spawnflags" "1" "origin" "1184 1976 -192" "classname" "item_spikes" } { "target" "t109" "targetname" "t108" "origin" "1240 2000 -184" "classname" "path_corner" } { "target" "t108" "targetname" "t109" "classname" "path_corner" "origin" "1240 1760 -184" } { "target" "t108" "angle" "90" "origin" "1240 1904 -168" "classname" "monster_ogre" "spawnflags" "1" } { "target" "t110" "classname" "trigger_once" "spawnflags" "256" "model" "*64" } { "targetname" "t110" "angle" "45" "origin" "1216 2088 -168" "classname" "monster_ogre" "spawnflags" "1281" } { "classname" "item_health" "origin" "1496 1768 -200" } { "target" "t111" "classname" "trigger_once" "model" "*65" } { "targetname" "t111" "angle" "315" "origin" "764 -60 -208" "classname" "monster_zombie" } { "targetname" "t111" "angle" "45" "origin" "764 436 -208" "classname" "monster_zombie" } { "targetname" "t111" "angle" "225" "origin" "284 -56 -208" "classname" "monster_zombie" "spawnflags" "256" } { "targetname" "t119" "wait" "-1" "speed" "40" "angle" "90" "classname" "func_door" "model" "*66" } { "origin" "1280 592 -128" "classname" "item_shells" } { "classname" "item_shells" "origin" "576 416 32" } { "classname" "item_spikes" "origin" "904 504 -128" "spawnflags" "1" } { "origin" "904 464 -128" "classname" "item_spikes" "spawnflags" "1" } { "classname" "item_health" "origin" "1024 912 -152" "spawnflags" "1" } { "classname" "item_spikes" "origin" "720 848 -184" "spawnflags" "1" } { "classname" "path_corner" "origin" "1224 1192 -176" "targetname" "t112" "target" "t113" } { "origin" "1216 896 -176" "classname" "path_corner" "targetname" "t113" "target" "t112" } { "classname" "monster_ogre" "origin" "1224 992 -160" "angle" "90" "target" "t112" } { "classname" "item_shells" "origin" "968 1600 -184" } { "classname" "item_artifact_super_damage" "origin" "1444 308 -104" } { "classname" "light" "origin" "992 -128 72" "light" "100" } { "classname" "item_shells" "origin" "1672 1008 -240" } { "classname" "item_health" "origin" "2264 1320 -224" } { "classname" "monster_wizard" "origin" "2120 1664 -72" "angle" "315" "spawnflags" "1" } { "classname" "item_health" "origin" "2016 392 -32" } { "classname" "monster_hell_knight" "origin" "360 1744 -208" "angle" "90" "targetname" "t114" "spawnflags" "257" } { "classname" "trigger_once" "target" "t114" "spawnflags" "256" "model" "*67" } { "classname" "item_health" "origin" "352 1464 -232" } { "spawnflags" "1" "origin" "352 1392 -232" "classname" "item_health" } { "classname" "item_armorInv" "origin" "744 1424 -448" } { "classname" "item_health" "origin" "-56 320 -232" } { "origin" "-16 320 -232" "classname" "item_health" } { "targetname" "t117" "classname" "trigger_teleport" "target" "t115" "spawnflags" "2" "model" "*68" } { "delay" ".5" "targetname" "t117" "classname" "trigger_teleport" "target" "t116" "spawnflags" "2" "model" "*69" } { "classname" "monster_wizard" "origin" "2928 1816 -152" "angle" "180" "targetname" "t117" } { "angle" "180" "origin" "2928 1768 -152" "classname" "monster_wizard" "targetname" "t117" } { "classname" "info_teleport_destination" "origin" "1824 1920 -184" "angle" "225" "targetname" "t115" } { "classname" "info_teleport_destination" "origin" "1880 1544 -184" "angle" "180" "targetname" "t116" } { "classname" "trigger_once" "target" "t117" "model" "*70" } { "classname" "monster_zombie" "origin" "764 388 -208" "angle" "0" "targetname" "t111" } { "angle" "0" "origin" "764 -12 -208" "classname" "monster_zombie" "targetname" "t111" } { "classname" "monster_zombie" "origin" "408 -56 -208" "angle" "270" "targetname" "t111" } { "classname" "light" "origin" "1200 672 -240" "light" "125" } { "classname" "item_spikes" "origin" "72 392 -64" "spawnflags" "1" } { "classname" "item_spikes" "origin" "2368 920 -224" } { "origin" "2032 976 -224" "classname" "item_spikes" } { "classname" "light" "origin" "1416 2096 -112" "light" "150" } { "light" "150" "origin" "1240 2096 -112" "classname" "light" } { "classname" "item_spikes" "origin" "464 1824 -240" } { "origin" "504 1824 -240" "classname" "item_spikes" } { "classname" "item_shells" "origin" "-96 1472 -232" "spawnflags" "1" } { "classname" "item_health" "origin" "528 -172 -232" } { "classname" "item_health" "origin" "40 -64 -64" } { "light" "225" "classname" "light_torch_small_walltorch" "origin" "122 -86 -8" } { "origin" "134 462 -8" "classname" "light_torch_small_walltorch" "light" "225" } { "light" "250" "origin" "678 446 92" "classname" "light_torch_small_walltorch" } { "classname" "light_torch_small_walltorch" "origin" "678 -70 92" "light" "250" } { "light" "150" "origin" "120 -56 -16" "classname" "light" } { "classname" "light" "origin" "136 424 -16" "light" "150" } { "light" "150" "origin" "600 184 296" "classname" "light" } { "classname" "light" "origin" "152 184 296" "light" "150" } { "light" "150" "origin" "368 376 296" "classname" "light" } { "classname" "light" "origin" "368 0 296" "light" "150" } { "light" "150" "origin" "352 192 232" "classname" "light" } { "light" "200" "origin" "64 408 168" "classname" "light" } { "classname" "light" "origin" "56 -48 168" "light" "200" } { "light" "125" "origin" "1520 1880 24" "classname" "light" } { "origin" "272 272 -232" "classname" "item_rockets" } { "targetname" "t45" "classname" "func_door" "angle" "-2" "sounds" "1" "wait" "-1" "model" "*71" } { "classname" "light" "origin" "416 -152 -152" "light" "125" } { "targetname" "t45" "angle" "90" "origin" "416 -120 -208" "classname" "monster_zombie" "spawnflags" "256" } { "origin" "400 524 -232" "classname" "item_health" } { "light" "125" "origin" "416 536 -152" "classname" "light" } { "targetname" "t45" "wait" "-1" "sounds" "1" "angle" "-2" "classname" "func_door" "model" "*72" } { "targetname" "t45" "angle" "270" "origin" "416 496 -208" "classname" "monster_zombie" "spawnflags" "256" } { "target" "t120" "wait" "-1" "angle" "270" "classname" "func_button" "model" "*73" } { "target" "t120" "wait" "-1" "angle" "90" "classname" "func_button" "model" "*74" } { "targetname" "t120" "target" "t119" "classname" "trigger_counter" "model" "*75" } { "light" "125" "origin" "1792 840 -112" "classname" "light" } { "classname" "light" "origin" "1584 840 -112" "light" "125" } { "light" "125" "origin" "1792 2280 -480" "classname" "light" } { "classname" "light" "origin" "1792 2144 -480" "light" "125" } { "origin" "1776 2232 -508" "classname" "item_health" } { "classname" "item_health" "origin" "1776 2192 -508" } { "light" "150" "origin" "1016 1696 -336" "classname" "light" } { "light" "125" "origin" "1080 1696 -280" "classname" "light" } { "light" "125" "origin" "1152 1696 -200" "classname" "light" } { "light" "150" "origin" "1096 1696 -352" "classname" "light" } { "classname" "trigger_secret" "model" "*76" } { "target" "t116" "classname" "trigger_teleport" "model" "*77" } { "spawnflags" "768" "angle" "315" "origin" "1400 1856 -176" "classname" "monster_ogre" } { "target" "t121" "targetname" "t122" "spawnflags" "768" "origin" "1824 2280 -344" "classname" "path_corner" } { "target" "t122" "targetname" "t121" "spawnflags" "768" "classname" "path_corner" "origin" "2080 2280 -344" } { "target" "t121" "spawnflags" "769" "angle" "180" "origin" "2128 2272 -328" "classname" "monster_demon1" } { "spawnflags" "2816" "origin" "1824 2072 -352" "classname" "item_shells" } { "spawnflags" "769" "angle" "90" "origin" "1792 2176 -144" "classname" "monster_wizard" } { "spawnflags" "769" "angle" "180" "origin" "2600 1640 -200" "classname" "monster_hell_knight" } { "spawnflags" "2816" "origin" "2096 1136 -32" "classname" "item_shells" } { "classname" "monster_wizard" "origin" "1872 1432 -72" "angle" "90" "spawnflags" "769" } { "classname" "monster_hell_knight" "origin" "2400 1032 -8" "angle" "180" "spawnflags" "769" } { "classname" "monster_demon1" "origin" "1000 496 -104" "angle" "0" "spawnflags" "768" } { "classname" "monster_demon1" "origin" "1240 2088 -168" "angle" "45" "spawnflags" "769" "targetname" "t110" } { "classname" "monster_hell_knight" "origin" "360 1936 -208" "angle" "270" "spawnflags" "769" "targetname" "t114" } { "classname" "item_shells" "origin" "16 1768 -232" "spawnflags" "2560" } { "spawnflags" "2560" "origin" "344 1576 -232" "classname" "item_shells" } { "classname" "trigger_changelevel" "map" "e2m4" "model" "*78" } { "classname" "light" "origin" "1136 -1144 264" "light" "250" } { "light" "250" "origin" "1264 -552 44" "classname" "light_flame_small_yellow" } { "classname" "light_flame_small_yellow" "origin" "1008 -552 44" "light" "250" } { "classname" "monster_demon1" "origin" "888 -120 56" "angle" "0" "spawnflags" "769" "targetname" "t66" } { "classname" "monster_hell_knight" "origin" "616 184 56" "angle" "0" "spawnflags" "768" } { "classname" "item_spikes" "origin" "880 216 32" "spawnflags" "2816" } { "classname" "monster_hell_knight" "origin" "1944 728 -8" "angle" "0" "spawnflags" "769" } { "classname" "light" "origin" "-48 1184 -156" "light" "200" "style" "10" } { "style" "10" "light" "200" "origin" "0 1024 -120" "classname" "light" } { "classname" "light" "origin" "48 800 -120" "light" "200" "style" "10" } { "style" "10" "light" "200" "origin" "0 600 -120" "classname" "light" } { "classname" "monster_hell_knight" "origin" "128 1088 -208" "angle" "225" "spawnflags" "1" } { "angle" "315" "origin" "-104 760 -208" "classname" "monster_hell_knight" "spawnflags" "1" } { "classname" "item_spikes" "origin" "-56 592 -232" } { "classname" "item_health" "origin" "-56 920 -232" } { "classname" "monster_demon1" "origin" "0 544 -208" "angle" "90" "target" "t123" "spawnflags" "769" } { "mangle" "20 315 0" "origin" "1568 2040 -88" "classname" "info_intermission" } { "classname" "item_shells" "origin" "1528 1968 -352" "spawnflags" "3584" } { "origin" "-88 1376 -232" "classname" "item_health" "spawnflags" "3585" } { "classname" "item_artifact_envirosuit" "origin" "1216 1696 -168" "spawnflags" "3584" } { "classname" "monster_demon1" "origin" "144 372 -208" "angle" "180" "spawnflags" "768" "targetname" "t123" } { "classname" "monster_demon1" "origin" "0 528 -208" "angle" "90" "spawnflags" "1025" } { "classname" "info_player_deathmatch" "origin" "1128 -840 -80" "angle" "90" } { "classname" "info_player_deathmatch" "origin" "656 184 -208" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "-24 1440 -208" "angle" "0" } { "classname" "info_player_deathmatch" "origin" "1240 1816 -168" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "1032 1568 -168" "angle" "0" } { "classname" "func_wall" "spawnflags" "1792" "model" "*79" } { "classname" "weapon_rocketlauncher" "origin" "184 1440 -232" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "1424 608 -104" "angle" "270" } { "classname" "info_player_deathmatch" "origin" "2272 680 -8" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "2240 1472 -200" "angle" "270" } { "classname" "weapon_supernailgun" "origin" "2236 1184 -32" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "2424 1824 -200" "angle" "180" } { "classname" "info_player_deathmatch" "origin" "1792 2072 -328" "angle" "270" } { "classname" "weapon_supershotgun" "origin" "1488 1584 -200" "spawnflags" "1792" } { "classname" "weapon_grenadelauncher" "origin" "88 184 -64" "spawnflags" "1792" } { "classname" "info_player_deathmatch" "origin" "1224 840 -168" "angle" "90" } { "classname" "weapon_nailgun" "origin" "1024 872 -152" "spawnflags" "1792" } { "classname" "weapon_supershotgun" "origin" "136 1760 -232" "spawnflags" "1792" } { "classname" "weapon_nailgun" "origin" "1976 2288 -352" "spawnflags" "1792" } { "classname" "weapon_lightning" "origin" "2128 1792 -352" "spawnflags" "1792" } { "classname" "item_cells" "origin" "1608 728 -128" "spawnflags" "1792" } { "spawnflags" "1792" "classname" "item_cells" "origin" "72 1032 -232" } { "classname" "item_cells" "origin" "1008 1328 -192" "spawnflags" "1792" } { "classname" "item_cells" "origin" "1304 -1160 -96" "spawnflags" "1792" } { "origin" "2272 1440 -224" "classname" "item_shells" "spawnflags" "2816" } { "origin" "224 1736 -232" "classname" "item_health" } { "classname" "info_intermission" "origin" "1328 -1168 192" "mangle" "20 120 0" } { "classname" "info_intermission" "origin" "1248 680 8" "mangle" "20 130 0" } { "classname" "info_intermission" "origin" "1280 1824 -104" "mangle" "10 180 0" } { "classname" "light" "origin" "-304 888 -80" "light" "150" } { "light" "150" "origin" "-304 712 -80" "classname" "light" } { "classname" "light" "origin" "-224 872 -8" "light" "125" } { "classname" "light" "origin" "-224 728 -8" "light" "125" } { "light" "150" "origin" "-178 706 -156" "classname" "light_torch_small_walltorch" } { "classname" "light" "origin" "-320 838 -138" "light" "100" } { "light" "100" "origin" "-320 774 -138" "classname" "light" } { "classname" "info_player_coop" "origin" "1192 -1088 -72" "angle" "90" } { "angle" "90" "origin" "1080 -1088 -72" "classname" "info_player_coop" } { "classname" "info_player_coop" "origin" "1008 -1112 -72" "angle" "90" } { "angle" "90" "origin" "1264 -1112 -72" "classname" "info_player_coop" } { "classname" "item_armor1" "origin" "784 1816 -232" } { "classname" "item_spikes" "origin" "-56 1472 -232" "spawnflags" "1" } { "classname" "item_rockets" "origin" "400 -172 -232" } { "classname" "func_wall" "spawnflags" "1792" "model" "*80" } { "spawnflags" "1792" "classname" "func_wall" "model" "*81" } { "classname" "path_corner" "origin" "1954 1770 -96" "targetname" "t124" "target" "t125" } { "classname" "path_corner" "origin" "1954 1770 -320" "targetname" "t125" "target" "t124" } { "classname" "weapon_grenadelauncher" "origin" "1688 720 -128" "spawnflags" "2048" } { "wait" "-1" "angle" "-2" "classname" "func_door" "targetname" "t126" "lip" "-8" "model" "*82" } { "classname" "func_door_secret" "angle" "90" "spawnflags" "2" "model" "*83" } { "classname" "light" "origin" "-224 832 -152" "light" "125" } { "classname" "trigger_counter" "target" "t126" "targetname" "t127" "spawnflags" "1" "count" "7" "model" "*84" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*85" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*86" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*87" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*88" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*89" } { "health" "1" "classname" "trigger_once" "target" "t127" "model" "*90" } { "classname" "trigger_once" "health" "1" "target" "t127" "model" "*91" } { "classname" "ambient_swamp1" "origin" "1338 -854 -104" } { "classname" "ambient_swamp2" "origin" "938 -854 -104" } { "classname" "ambient_drip" "origin" "1138 -854 -176" } { "classname" "ambient_drip" "origin" "1650 -862 -192" } { "classname" "ambient_drip" "origin" "1674 -438 -192" } { "classname" "ambient_drip" "origin" "1682 2 -48" } { "classname" "ambient_swamp1" "origin" "1674 1986 -280" } { "classname" "ambient_swamp2" "origin" "1826 2378 -280" } { "classname" "ambient_swamp1" "origin" "2258 2058 -280" } { "classname" "ambient_drip" "origin" "746 1370 -376" } { "classname" "ambient_drip" "origin" "762 906 -240" } { "origin" "1034 722 -240" "classname" "ambient_drip" } { "classname" "ambient_drip" "origin" "554 1818 -352" } { "origin" "1002 1810 -352" "classname" "ambient_drip" } { "speed" "35" "classname" "func_door" "wait" "-1" "angle" "-2" "sounds" "1" "targetname" "t101" "model" "*92" } { "classname" "light" "origin" "1440 296 -80" "light" "125" } { "origin" "1792 792 -240" "classname" "item_spikes" } // // load keybindings // // commands with a leading + will also be called for key up events with // the + changed to a - unbindall // // character controls // bind ALT +strafe bind , +moveleft bind a +moveleft bind . +moveright bind d +moveright bind DEL +lookdown bind PGDN +lookup bind END centerview bind e +moveup bind c +movedown bind SHIFT +speed bind CTRL +attack bind UPARROW +forward bind w +forward bind DOWNARROW +back bind s +back bind LEFTARROW +left bind RIGHTARROW +right bind SPACE +jump //bind ENTER +jump bind TAB +showscores bind 1 "impulse 1" bind 2 "impulse 2" bind 3 "impulse 3" bind 4 "impulse 4" bind 5 "impulse 5" bind 6 "impulse 6" bind 7 "impulse 7" bind 8 "impulse 8" bind 0 "impulse 0" bind / "impulse 10" // change weapon bind MWHEELDOWN "impulse 10" bind MWHEELUP "impulse 12" // zoom alias zoom_in "sensitivity 2;fov 90;wait;fov 70;wait;fov 50;wait;fov 30;wait;fov 10;wait;fov 5;bind F11 zoom_out" alias zoom_out "sensitivity 4;fov 5;wait;fov 10;wait;fov 30;wait;fov 50;wait;fov 70;wait;fov 90;bind F11 zoom_in; sensitivity 3" bind F11 zoom_in // Function keys bind F1 "help" bind F2 "menu_save" bind F3 "menu_load" bind F4 "menu_options" bind F5 "menu_multiplayer" bind F6 "echo Quicksaving...; wait; save quick" bind F9 "echo Quickloading...; wait; load quick" bind F10 "quit" bind F12 "screenshot" // mouse options bind \ +mlook // // client environment commands // bind PAUSE "pause" bind ESCAPE "togglemenu" bind ~ "toggleconsole" bind ` "toggleconsole" bind t "messagemode" bind + "sizeup" bind = "sizeup" bind - "sizedown" bind INS +klook // // mouse buttons // bind MOUSE1 +attack //bind MOUSE2 +forward bind MOUSE2 +jump //bind MOUSE3 +mlook // // default cvars // gamma 1.0 volume 0.7 sensitivity 3 //viewsize 100 viewsize 110 scr_conscale 1.6 scr_menuscale 1.6 scr_sbarscale 1.6 // default to mouse-look enabled +mlook gfx/conback.lmp����������������������������������������� �����maps/e1m1.ent���������������������������������������������Þf��maps/e1m2.ent�������������������������������������������òf�G¡��maps/e1m4.ent�������������������������������������������9�ת��maps/e2m2.ent�������������������������������������������³�+j��maps/e2m3.ent�������������������������������������������;�=˜��maps/e2m7.ent�������������������������������������������xµ�Å��default.cfg���������������������������������������������ùz�ÿ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/r_alias.c�������������������������������������������������������������������0000644�0000000�0000000�00000070070�12577611311�015305� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //r_alias.c -- alias model rendering #include "quakedef.h" extern cvar_t r_drawflat, gl_overbright_models, gl_fullbrights, r_lerpmodels, r_lerpmove; //johnfitz //up to 16 color translated skins gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz -- changed to an array of pointers #define NUMVERTEXNORMALS 162 float r_avertexnormals[NUMVERTEXNORMALS][3] = { #include "anorms.h" }; extern vec3_t lightcolor; //johnfitz -- replaces "float shadelight" for lit support // precalculated dot products for quantized angles #define SHADEDOT_QUANT 16 float r_avertexnormal_dots[SHADEDOT_QUANT][256] = { #include "anorm_dots.h" }; extern vec3_t lightspot; float *shadedots = r_avertexnormal_dots[0]; vec3_t shadevector; float entalpha; //johnfitz qboolean overbright; //johnfitz qboolean shading = true; //johnfitz -- if false, disable vertex shading for various reasons (fullbright, r_lightmap, showtris, etc) //johnfitz -- struct for passing lerp information to drawing functions typedef struct { short pose1; short pose2; float blend; vec3_t origin; vec3_t angles; } lerpdata_t; //johnfitz static GLuint r_alias_program; // uniforms used in vert shader static GLuint blendLoc; static GLuint shadevectorLoc; static GLuint lightColorLoc; // uniforms used in frag shader static GLuint texLoc; static GLuint fullbrightTexLoc; static GLuint useFullbrightTexLoc; static GLuint useOverbrightLoc; static const GLint pose1VertexAttrIndex = 0; static const GLint pose1NormalAttrIndex = 1; static const GLint pose2VertexAttrIndex = 2; static const GLint pose2NormalAttrIndex = 3; static const GLint texCoordsAttrIndex = 4; /* ============= GLARB_GetXYZOffset Returns the offset of the first vertex's meshxyz_t.xyz in the vbo for the given model and pose. ============= */ static void *GLARB_GetXYZOffset (aliashdr_t *hdr, int pose) { meshxyz_t dummy; int xyzoffs = ((char*)&dummy.xyz - (char*)&dummy); return (void *) (currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + xyzoffs); } /* ============= GLARB_GetNormalOffset Returns the offset of the first vertex's meshxyz_t.normal in the vbo for the given model and pose. ============= */ static void *GLARB_GetNormalOffset (aliashdr_t *hdr, int pose) { meshxyz_t dummy; int normaloffs = ((char*)&dummy.normal - (char*)&dummy); return (void *)(currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + normaloffs); } /* ============= GLAlias_CreateShaders ============= */ void GLAlias_CreateShaders (void) { const glsl_attrib_binding_t bindings[] = { { "TexCoords", texCoordsAttrIndex }, { "Pose1Vert", pose1VertexAttrIndex }, { "Pose1Normal", pose1NormalAttrIndex }, { "Pose2Vert", pose2VertexAttrIndex }, { "Pose2Normal", pose2NormalAttrIndex } }; const GLchar *vertSource = \ "#version 110\n" "\n" "uniform float Blend;\n" "uniform vec3 ShadeVector;\n" "uniform vec4 LightColor;\n" "attribute vec4 TexCoords; // only xy are used \n" "attribute vec4 Pose1Vert;\n" "attribute vec3 Pose1Normal;\n" "attribute vec4 Pose2Vert;\n" "attribute vec3 Pose2Normal;\n" "float r_avertexnormal_dot(vec3 vertexnormal) // from MH \n" "{\n" " float dot = dot(vertexnormal, ShadeVector);\n" " // wtf - this reproduces anorm_dots within as reasonable a degree of tolerance as the >= 0 case\n" " if (dot < 0.0)\n" " return 1.0 + dot * (13.0 / 44.0);\n" " else\n" " return 1.0 + dot;\n" "}\n" "void main()\n" "{\n" " gl_TexCoord[0] = TexCoords;\n" " vec4 lerpedVert = mix(Pose1Vert, Pose2Vert, Blend);\n" " gl_Position = gl_ModelViewProjectionMatrix * lerpedVert;\n" " float dot1 = r_avertexnormal_dot(Pose1Normal);\n" " float dot2 = r_avertexnormal_dot(Pose2Normal);\n" " gl_FrontColor = LightColor * vec4(vec3(mix(dot1, dot2, Blend)), 1.0);\n" " // fog\n" " vec3 ecPosition = vec3(gl_ModelViewMatrix * lerpedVert);\n" " gl_FogFragCoord = abs(ecPosition.z);\n" "}\n"; const GLchar *fragSource = \ "#version 110\n" "\n" "uniform sampler2D Tex;\n" "uniform sampler2D FullbrightTex;\n" "uniform bool UseFullbrightTex;\n" "uniform bool UseOverbright;\n" "void main()\n" "{\n" " vec4 result = texture2D(Tex, gl_TexCoord[0].xy);\n" " result *= gl_Color;\n" " if (UseOverbright)\n" " result.rgb *= 2.0;\n" " if (UseFullbrightTex)\n" " result += texture2D(FullbrightTex, gl_TexCoord[0].xy);\n" " result = clamp(result, 0.0, 1.0);\n" " // apply GL_EXP2 fog (from the orange book)\n" " float fog = exp(-gl_Fog.density * gl_Fog.density * gl_FogFragCoord * gl_FogFragCoord);\n" " fog = clamp(fog, 0.0, 1.0);\n" " result = mix(gl_Fog.color, result, fog);\n" " result.a = gl_Color.a;\n" " gl_FragColor = result;\n" "}\n"; if (!gl_glsl_alias_able) return; r_alias_program = GL_CreateProgram (vertSource, fragSource, sizeof(bindings)/sizeof(bindings[0]), bindings); if (r_alias_program != 0) { // get uniform locations blendLoc = GL_GetUniformLocation (&r_alias_program, "Blend"); shadevectorLoc = GL_GetUniformLocation (&r_alias_program, "ShadeVector"); lightColorLoc = GL_GetUniformLocation (&r_alias_program, "LightColor"); texLoc = GL_GetUniformLocation (&r_alias_program, "Tex"); fullbrightTexLoc = GL_GetUniformLocation (&r_alias_program, "FullbrightTex"); useFullbrightTexLoc = GL_GetUniformLocation (&r_alias_program, "UseFullbrightTex"); useOverbrightLoc = GL_GetUniformLocation (&r_alias_program, "UseOverbright"); } } /* ============= GL_DrawAliasFrame_GLSL -- ericw Optimized alias model drawing codepath. Compared to the original GL_DrawAliasFrame, this makes 1 draw call, no vertex data is uploaded (it's already in the r_meshvbo and r_meshindexesvbo static VBOs), and lerping and lighting is done in the vertex shader. Supports optional overbright, optional fullbright pixels. Based on code by MH from RMQEngine ============= */ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltexture_t *tx, gltexture_t *fb) { float blend; if (lerpdata.pose1 != lerpdata.pose2) { blend = lerpdata.blend; } else // poses the same means either 1. the entity has paused its animation, or 2. r_lerpmodels is disabled { blend = 0; } GL_UseProgramFunc (r_alias_program); GL_BindBuffer (GL_ARRAY_BUFFER, currententity->model->meshvbo); GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, currententity->model->meshindexesvbo); GL_EnableVertexAttribArrayFunc (texCoordsAttrIndex); GL_EnableVertexAttribArrayFunc (pose1VertexAttrIndex); GL_EnableVertexAttribArrayFunc (pose2VertexAttrIndex); GL_EnableVertexAttribArrayFunc (pose1NormalAttrIndex); GL_EnableVertexAttribArrayFunc (pose2NormalAttrIndex); GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, 0, (void *)(intptr_t)currententity->model->vbostofs); GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_t), GLARB_GetXYZOffset (paliashdr, lerpdata.pose1)); GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_t), GLARB_GetXYZOffset (paliashdr, lerpdata.pose2)); // GL_TRUE to normalize the signed bytes to [-1 .. 1] GL_VertexAttribPointerFunc (pose1NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_t), GLARB_GetNormalOffset (paliashdr, lerpdata.pose1)); GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_t), GLARB_GetNormalOffset (paliashdr, lerpdata.pose2)); // set uniforms GL_Uniform1fFunc (blendLoc, blend); GL_Uniform3fFunc (shadevectorLoc, shadevector[0], shadevector[1], shadevector[2]); GL_Uniform4fFunc (lightColorLoc, lightcolor[0], lightcolor[1], lightcolor[2], entalpha); GL_Uniform1iFunc (texLoc, 0); GL_Uniform1iFunc (fullbrightTexLoc, 1); GL_Uniform1iFunc (useFullbrightTexLoc, (fb != NULL) ? 1 : 0); GL_Uniform1fFunc (useOverbrightLoc, overbright ? 1 : 0); // set textures GL_SelectTexture (GL_TEXTURE0); GL_Bind (tx); if (fb) { GL_SelectTexture (GL_TEXTURE1); GL_Bind (fb); } // draw glDrawElements (GL_TRIANGLES, paliashdr->numindexes, GL_UNSIGNED_SHORT, (void *)(intptr_t)currententity->model->vboindexofs); // clean up GL_DisableVertexAttribArrayFunc (texCoordsAttrIndex); GL_DisableVertexAttribArrayFunc (pose1VertexAttrIndex); GL_DisableVertexAttribArrayFunc (pose2VertexAttrIndex); GL_DisableVertexAttribArrayFunc (pose1NormalAttrIndex); GL_DisableVertexAttribArrayFunc (pose2NormalAttrIndex); GL_UseProgramFunc (0); GL_SelectTexture (GL_TEXTURE0); rs_aliaspasses += paliashdr->numtris; } /* ============= GL_DrawAliasFrame -- johnfitz -- rewritten to support colored light, lerping, entalpha, multitexture, and r_drawflat ============= */ void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata) { float vertcolor[4]; trivertx_t *verts1, *verts2; int *commands; int count; float u,v; float blend, iblend; qboolean lerping; if (lerpdata.pose1 != lerpdata.pose2) { lerping = true; verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); verts2 = verts1; verts1 += lerpdata.pose1 * paliashdr->poseverts; verts2 += lerpdata.pose2 * paliashdr->poseverts; blend = lerpdata.blend; iblend = 1.0f - blend; } else // poses the same means either 1. the entity has paused its animation, or 2. r_lerpmodels is disabled { lerping = false; verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); verts2 = verts1; // avoid bogus compiler warning verts1 += lerpdata.pose1 * paliashdr->poseverts; blend = iblend = 0; // avoid bogus compiler warning } commands = (int *)((byte *)paliashdr + paliashdr->commands); vertcolor[3] = entalpha; //never changes, so there's no need to put this inside the loop while (1) { // get the vertex count and primitive type count = *commands++; if (!count) break; // done if (count < 0) { count = -count; glBegin (GL_TRIANGLE_FAN); } else glBegin (GL_TRIANGLE_STRIP); do { u = ((float *)commands)[0]; v = ((float *)commands)[1]; if (mtexenabled) { GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, u, v); GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, u, v); } else glTexCoord2f (u, v); commands += 2; if (shading) { if (r_drawflat_cheatsafe) { srand(count * (unsigned int)(src_offset_t)commands); glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); } else if (lerping) { vertcolor[0] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[0]; vertcolor[1] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[1]; vertcolor[2] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[2]; glColor4fv (vertcolor); } else { vertcolor[0] = shadedots[verts1->lightnormalindex] * lightcolor[0]; vertcolor[1] = shadedots[verts1->lightnormalindex] * lightcolor[1]; vertcolor[2] = shadedots[verts1->lightnormalindex] * lightcolor[2]; glColor4fv (vertcolor); } } if (lerping) { glVertex3f (verts1->v[0]*iblend + verts2->v[0]*blend, verts1->v[1]*iblend + verts2->v[1]*blend, verts1->v[2]*iblend + verts2->v[2]*blend); verts1++; verts2++; } else { glVertex3f (verts1->v[0], verts1->v[1], verts1->v[2]); verts1++; } } while (--count); glEnd (); } rs_aliaspasses += paliashdr->numtris; } /* ================= R_SetupAliasFrame -- johnfitz -- rewritten to support lerping ================= */ void R_SetupAliasFrame (aliashdr_t *paliashdr, int frame, lerpdata_t *lerpdata) { entity_t *e = currententity; int posenum, numposes; if ((frame >= paliashdr->numframes) || (frame < 0)) { Con_DPrintf ("R_AliasSetupFrame: no such frame %d for '%s'\n", frame, e->model->name); frame = 0; } posenum = paliashdr->frames[frame].firstpose; numposes = paliashdr->frames[frame].numposes; if (numposes > 1) { e->lerptime = paliashdr->frames[frame].interval; posenum += (int)(cl.time / e->lerptime) % numposes; } else e->lerptime = 0.1; if (e->lerpflags & LERP_RESETANIM) //kill any lerp in progress { e->lerpstart = 0; e->previouspose = posenum; e->currentpose = posenum; e->lerpflags -= LERP_RESETANIM; } else if (e->currentpose != posenum) // pose changed, start new lerp { if (e->lerpflags & LERP_RESETANIM2) //defer lerping one more time { e->lerpstart = 0; e->previouspose = posenum; e->currentpose = posenum; e->lerpflags -= LERP_RESETANIM2; } else { e->lerpstart = cl.time; e->previouspose = e->currentpose; e->currentpose = posenum; } } //set up values if (r_lerpmodels.value && !(e->model->flags & MOD_NOLERP && r_lerpmodels.value != 2)) { if (e->lerpflags & LERP_FINISH && numposes == 1) lerpdata->blend = CLAMP (0, (cl.time - e->lerpstart) / (e->lerpfinish - e->lerpstart), 1); else lerpdata->blend = CLAMP (0, (cl.time - e->lerpstart) / e->lerptime, 1); lerpdata->pose1 = e->previouspose; lerpdata->pose2 = e->currentpose; } else //don't lerp { lerpdata->blend = 1; lerpdata->pose1 = posenum; lerpdata->pose2 = posenum; } } /* ================= R_SetupEntityTransform -- johnfitz -- set up transform part of lerpdata ================= */ void R_SetupEntityTransform (entity_t *e, lerpdata_t *lerpdata) { float blend; vec3_t d; int i; // if LERP_RESETMOVE, kill any lerps in progress if (e->lerpflags & LERP_RESETMOVE) { e->movelerpstart = 0; VectorCopy (e->origin, e->previousorigin); VectorCopy (e->origin, e->currentorigin); VectorCopy (e->angles, e->previousangles); VectorCopy (e->angles, e->currentangles); e->lerpflags -= LERP_RESETMOVE; } else if (!VectorCompare (e->origin, e->currentorigin) || !VectorCompare (e->angles, e->currentangles)) // origin/angles changed, start new lerp { e->movelerpstart = cl.time; VectorCopy (e->currentorigin, e->previousorigin); VectorCopy (e->origin, e->currentorigin); VectorCopy (e->currentangles, e->previousangles); VectorCopy (e->angles, e->currentangles); } //set up values if (r_lerpmove.value && e != &cl.viewent && e->lerpflags & LERP_MOVESTEP) { if (e->lerpflags & LERP_FINISH) blend = CLAMP (0, (cl.time - e->movelerpstart) / (e->lerpfinish - e->movelerpstart), 1); else blend = CLAMP (0, (cl.time - e->movelerpstart) / 0.1, 1); //translation VectorSubtract (e->currentorigin, e->previousorigin, d); lerpdata->origin[0] = e->previousorigin[0] + d[0] * blend; lerpdata->origin[1] = e->previousorigin[1] + d[1] * blend; lerpdata->origin[2] = e->previousorigin[2] + d[2] * blend; //rotation VectorSubtract (e->currentangles, e->previousangles, d); for (i = 0; i < 3; i++) { if (d[i] > 180) d[i] -= 360; if (d[i] < -180) d[i] += 360; } lerpdata->angles[0] = e->previousangles[0] + d[0] * blend; lerpdata->angles[1] = e->previousangles[1] + d[1] * blend; lerpdata->angles[2] = e->previousangles[2] + d[2] * blend; } else //don't lerp { VectorCopy (e->origin, lerpdata->origin); VectorCopy (e->angles, lerpdata->angles); } } /* ================= R_SetupAliasLighting -- johnfitz -- broken out from R_DrawAliasModel and rewritten ================= */ void R_SetupAliasLighting (entity_t *e) { vec3_t dist; float add; int i; int quantizedangle; float radiansangle; R_LightPoint (e->origin); //add dlights for (i=0 ; i<MAX_DLIGHTS ; i++) { if (cl_dlights[i].die >= cl.time) { VectorSubtract (currententity->origin, cl_dlights[i].origin, dist); add = cl_dlights[i].radius - VectorLength(dist); if (add > 0) VectorMA (lightcolor, add, cl_dlights[i].color, lightcolor); } } // minimum light value on gun (24) if (e == &cl.viewent) { add = 72.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]); if (add > 0.0f) { lightcolor[0] += add / 3.0f; lightcolor[1] += add / 3.0f; lightcolor[2] += add / 3.0f; } } // minimum light value on players (8) if (currententity > cl_entities && currententity <= cl_entities + cl.maxclients) { add = 24.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]); if (add > 0.0f) { lightcolor[0] += add / 3.0f; lightcolor[1] += add / 3.0f; lightcolor[2] += add / 3.0f; } } // clamp lighting so it doesn't overbright as much (96) if (overbright) { add = 288.0f / (lightcolor[0] + lightcolor[1] + lightcolor[2]); if (add < 1.0f) VectorScale(lightcolor, add, lightcolor); } //hack up the brightness when fullbrights but no overbrights (256) if (gl_fullbrights.value && !gl_overbright_models.value) if (e->model->flags & MOD_FBRIGHTHACK) { lightcolor[0] = 256.0f; lightcolor[1] = 256.0f; lightcolor[2] = 256.0f; } quantizedangle = ((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1); //ericw -- shadevector is passed to the shader to compute shadedots inside the //shader, see GLAlias_CreateShaders() radiansangle = (quantizedangle / 16.0) * 2.0 * 3.14159; shadevector[0] = cos(-radiansangle); shadevector[1] = sin(-radiansangle); shadevector[2] = 1; VectorNormalize(shadevector); //ericw -- shadedots = r_avertexnormal_dots[quantizedangle]; VectorScale (lightcolor, 1.0f / 200.0f, lightcolor); } /* ================= R_DrawAliasModel -- johnfitz -- almost completely rewritten ================= */ void R_DrawAliasModel (entity_t *e) { aliashdr_t *paliashdr; int i, anim; gltexture_t *tx, *fb; lerpdata_t lerpdata; // // setup pose/lerp data -- do it first so we don't miss updates due to culling // paliashdr = (aliashdr_t *)Mod_Extradata (e->model); R_SetupAliasFrame (paliashdr, e->frame, &lerpdata); R_SetupEntityTransform (e, &lerpdata); // // cull it // if (R_CullModelForEntity(e)) return; // // transform it // glPushMatrix (); R_RotateForEntity (lerpdata.origin, lerpdata.angles); glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); // // random stuff // if (gl_smoothmodels.value && !r_drawflat_cheatsafe) glShadeModel (GL_SMOOTH); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); overbright = gl_overbright_models.value; shading = true; // // set up for alpha blending // if (r_drawflat_cheatsafe || r_lightmap_cheatsafe) //no alpha in drawflat or lightmap mode entalpha = 1; else entalpha = ENTALPHA_DECODE(e->alpha); if (entalpha == 0) goto cleanup; if (entalpha < 1) { if (!gl_texture_env_combine) overbright = false; //overbright can't be done in a single pass without combiners glDepthMask(GL_FALSE); glEnable(GL_BLEND); } // // set up lighting // rs_aliaspolys += paliashdr->numtris; R_SetupAliasLighting (e); // // set up textures // GL_DisableMultitexture(); anim = (int)(cl.time*10) & 3; if ((e->skinnum >= paliashdr->numskins) || (e->skinnum < 0)) { Con_DPrintf ("R_DrawAliasModel: no such skin # %d for '%s'\n", e->skinnum, e->model->name); tx = NULL; // NULL will give the checkerboard texture fb = NULL; } else { tx = paliashdr->gltextures[e->skinnum][anim]; fb = paliashdr->fbtextures[e->skinnum][anim]; } if (e->colormap != vid.colormap && !gl_nocolors.value) { i = e - cl_entities; if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) tx = playertextures[i - 1]; } if (!gl_fullbrights.value) fb = NULL; // // draw it // if (r_drawflat_cheatsafe) { glDisable (GL_TEXTURE_2D); GL_DrawAliasFrame (paliashdr, lerpdata); glEnable (GL_TEXTURE_2D); srand((int) (cl.time * 1000)); //restore randomness } else if (r_fullbright_cheatsafe) { GL_Bind (tx); shading = false; glColor4f(1,1,1,entalpha); GL_DrawAliasFrame (paliashdr, lerpdata); if (fb) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_Bind(fb); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); glColor3f(entalpha,entalpha,entalpha); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); } } else if (r_lightmap_cheatsafe) { glDisable (GL_TEXTURE_2D); shading = false; glColor3f(1,1,1); GL_DrawAliasFrame (paliashdr, lerpdata); glEnable (GL_TEXTURE_2D); } // call fast path if possible. if the shader compliation failed for some reason, // r_alias_program will be 0. else if (r_alias_program != 0) { GL_DrawAliasFrame_GLSL (paliashdr, lerpdata, tx, fb); } else if (overbright) { if (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && fb) //case 1: everything in one pass { GL_Bind (tx); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); GL_EnableMultitexture(); // selects TEXTURE1 GL_Bind (fb); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); glEnable(GL_BLEND); GL_DrawAliasFrame (paliashdr, lerpdata); glDisable(GL_BLEND); GL_DisableMultitexture(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else if (gl_texture_env_combine) //case 2: overbright in one pass, then fullbright pass { // first pass GL_Bind(tx); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); GL_DrawAliasFrame (paliashdr, lerpdata); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // second pass if (fb) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_Bind(fb); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); shading = false; glColor3f(entalpha,entalpha,entalpha); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } } else //case 3: overbright in two passes, then fullbright pass { // first pass GL_Bind(tx); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DrawAliasFrame (paliashdr, lerpdata); // second pass -- additive with black fog, to double the object colors but not the fog color glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); // third pass if (fb) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_Bind(fb); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); shading = false; glColor3f(entalpha,entalpha,entalpha); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } } } else { if (gl_mtexable && gl_texture_env_add && fb) //case 4: fullbright mask using multitexture { GL_DisableMultitexture(); // selects TEXTURE0 GL_Bind (tx); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_EnableMultitexture(); // selects TEXTURE1 GL_Bind (fb); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); glEnable(GL_BLEND); GL_DrawAliasFrame (paliashdr, lerpdata); glDisable(GL_BLEND); GL_DisableMultitexture(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else //case 5: fullbright mask without multitexture { // first pass GL_Bind(tx); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DrawAliasFrame (paliashdr, lerpdata); // second pass if (fb) { GL_Bind(fb); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); shading = false; glColor3f(entalpha,entalpha,entalpha); Fog_StartAdditive (); GL_DrawAliasFrame (paliashdr, lerpdata); Fog_StopAdditive (); glDepthMask(GL_TRUE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); } } } cleanup: glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glShadeModel (GL_FLAT); glDepthMask(GL_TRUE); glDisable(GL_BLEND); glColor3f(1,1,1); glPopMatrix (); } //johnfitz -- values for shadow matrix #define SHADOW_SKEW_X -0.7 //skew along x axis. -0.7 to mimic glquake shadows #define SHADOW_SKEW_Y 0 //skew along y axis. 0 to mimic glquake shadows #define SHADOW_VSCALE 0 //0=completely flat #define SHADOW_HEIGHT 0.1 //how far above the floor to render the shadow //johnfitz /* ============= GL_DrawAliasShadow -- johnfitz -- rewritten TODO: orient shadow onto "lightplane" (a global mplane_t*) ============= */ void GL_DrawAliasShadow (entity_t *e) { float shadowmatrix[16] = {1, 0, 0, 0, 0, 1, 0, 0, SHADOW_SKEW_X, SHADOW_SKEW_Y, SHADOW_VSCALE, 0, 0, 0, SHADOW_HEIGHT, 1}; float lheight; aliashdr_t *paliashdr; lerpdata_t lerpdata; if (R_CullModelForEntity(e)) return; if (e == &cl.viewent || e->model->flags & MOD_NOSHADOW) return; entalpha = ENTALPHA_DECODE(e->alpha); if (entalpha == 0) return; paliashdr = (aliashdr_t *)Mod_Extradata (e->model); R_SetupAliasFrame (paliashdr, e->frame, &lerpdata); R_SetupEntityTransform (e, &lerpdata); R_LightPoint (e->origin); lheight = currententity->origin[2] - lightspot[2]; // set up matrix glPushMatrix (); glTranslatef (lerpdata.origin[0], lerpdata.origin[1], lerpdata.origin[2]); glTranslatef (0,0,-lheight); glMultMatrixf (shadowmatrix); glTranslatef (0,0,lheight); glRotatef (lerpdata.angles[1], 0, 0, 1); glRotatef (-lerpdata.angles[0], 0, 1, 0); glRotatef (lerpdata.angles[2], 1, 0, 0); glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); // draw it glDepthMask(GL_FALSE); glEnable (GL_BLEND); GL_DisableMultitexture (); glDisable (GL_TEXTURE_2D); shading = false; glColor4f(0,0,0,entalpha * 0.5); GL_DrawAliasFrame (paliashdr, lerpdata); glEnable (GL_TEXTURE_2D); glDisable (GL_BLEND); glDepthMask(GL_TRUE); //clean up glPopMatrix (); } /* ================= R_DrawAliasModel_ShowTris -- johnfitz ================= */ void R_DrawAliasModel_ShowTris (entity_t *e) { aliashdr_t *paliashdr; lerpdata_t lerpdata; if (R_CullModelForEntity(e)) return; paliashdr = (aliashdr_t *)Mod_Extradata (e->model); R_SetupAliasFrame (paliashdr, e->frame, &lerpdata); R_SetupEntityTransform (e, &lerpdata); glPushMatrix (); R_RotateForEntity (lerpdata.origin,lerpdata.angles); glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); shading = false; glColor3f(1,1,1); GL_DrawAliasFrame (paliashdr, lerpdata); glPopMatrix (); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/screen.h��������������������������������������������������������������������0000644�0000000�0000000�00000004147�12407762022�015157� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_SCREEN_H #define _QUAKE_SCREEN_H // screen.h void SCR_Init (void); void SCR_LoadPics (void); void SCR_UpdateScreen (void); void SCR_SizeUp (void); void SCR_SizeDown (void); void SCR_BringDownConsole (void); void SCR_CenterPrint (const char *str); void SCR_BeginLoadingPlaque (void); void SCR_EndLoadingPlaque (void); int SCR_ModalMessage (const char *text, float timeout); //johnfitz -- added timeout extern float scr_con_current; extern float scr_conlines; // lines of console to display extern int sb_lines; extern int clearnotify; // set to 0 whenever notify text is drawn extern qboolean scr_disabled_for_loading; extern qboolean scr_skipupdate; extern cvar_t scr_viewsize; extern cvar_t scr_sbaralpha; //johnfitz void SCR_UpdateWholeScreen (void); //johnfitz -- stuff for 2d drawing control typedef enum { CANVAS_NONE, CANVAS_DEFAULT, CANVAS_CONSOLE, CANVAS_MENU, CANVAS_SBAR, CANVAS_WARPIMAGE, CANVAS_CROSSHAIR, CANVAS_BOTTOMLEFT, CANVAS_BOTTOMRIGHT, CANVAS_TOPRIGHT, CANVAS_INVALID = -1 } canvastype; extern cvar_t scr_menuscale; extern cvar_t scr_sbarscale; extern cvar_t scr_conwidth; extern cvar_t scr_conscale; extern cvar_t scr_scale; extern cvar_t scr_crosshairscale; //johnfitz extern int scr_tileclear_updates; //johnfitz #endif /* _QUAKE_SCREEN_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_rmisc.c������������������������������������������������������������������0000644�0000000�0000000�00000035471�12577611311�015500� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // r_misc.c #include "quakedef.h" //johnfitz -- new cvars extern cvar_t r_stereo; extern cvar_t r_stereodepth; extern cvar_t r_clearcolor; extern cvar_t r_drawflat; extern cvar_t r_flatlightstyles; extern cvar_t gl_fullbrights; extern cvar_t gl_farclip; extern cvar_t gl_overbright; extern cvar_t gl_overbright_models; extern cvar_t r_waterquality; extern cvar_t r_oldwater; extern cvar_t r_waterwarp; extern cvar_t r_oldskyleaf; extern cvar_t r_drawworld; extern cvar_t r_showtris; extern cvar_t r_showbboxes; extern cvar_t r_lerpmodels; extern cvar_t r_lerpmove; extern cvar_t r_nolerp_list; extern cvar_t r_noshadow_list; //johnfitz extern cvar_t gl_zfix; // QuakeSpasm z-fighting fix extern gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz /* ==================== GL_Overbright_f -- johnfitz ==================== */ static void GL_Overbright_f (cvar_t *var) { R_RebuildAllLightmaps (); } /* ==================== GL_Fullbrights_f -- johnfitz ==================== */ static void GL_Fullbrights_f (cvar_t *var) { TexMgr_ReloadNobrightImages (); } /* ==================== R_SetClearColor_f -- johnfitz ==================== */ static void R_SetClearColor_f (cvar_t *var) { byte *rgb; int s; s = (int)r_clearcolor.value & 0xFF; rgb = (byte*)(d_8to24table + s); glClearColor (rgb[0]/255.0,rgb[1]/255.0,rgb[2]/255.0,0); } /* ==================== R_Novis_f -- johnfitz ==================== */ static void R_VisChanged (cvar_t *var) { extern int vis_changed; vis_changed = 1; } /* =============== R_Model_ExtraFlags_List_f -- johnfitz -- called when r_nolerp_list or r_noshadow_list cvar changes =============== */ static void R_Model_ExtraFlags_List_f (cvar_t *var) { int i; for (i=0; i < MAX_MODELS; i++) Mod_SetExtraFlags (cl.model_precache[i]); } /* ==================== R_SetWateralpha_f -- ericw ==================== */ static void R_SetWateralpha_f (cvar_t *var) { map_wateralpha = var->value; } /* ==================== R_SetLavaalpha_f -- ericw ==================== */ static void R_SetLavaalpha_f (cvar_t *var) { map_lavaalpha = var->value; } /* ==================== R_SetTelealpha_f -- ericw ==================== */ static void R_SetTelealpha_f (cvar_t *var) { map_telealpha = var->value; } /* ==================== R_SetSlimealpha_f -- ericw ==================== */ static void R_SetSlimealpha_f (cvar_t *var) { map_slimealpha = var->value; } /* ==================== GL_WaterAlphaForSurfface -- ericw ==================== */ float GL_WaterAlphaForSurface (msurface_t *fa) { if (fa->flags & SURF_DRAWLAVA) return map_lavaalpha > 0 ? map_lavaalpha : map_wateralpha; else if (fa->flags & SURF_DRAWTELE) return map_telealpha > 0 ? map_telealpha : map_wateralpha; else if (fa->flags & SURF_DRAWSLIME) return map_slimealpha > 0 ? map_slimealpha : map_wateralpha; else return map_wateralpha; } /* =============== R_Init =============== */ void R_Init (void) { extern cvar_t gl_finish; Cmd_AddCommand ("timerefresh", R_TimeRefresh_f); Cmd_AddCommand ("pointfile", R_ReadPointFile_f); Cvar_RegisterVariable (&r_norefresh); Cvar_RegisterVariable (&r_lightmap); Cvar_RegisterVariable (&r_fullbright); Cvar_RegisterVariable (&r_drawentities); Cvar_RegisterVariable (&r_drawviewmodel); Cvar_RegisterVariable (&r_shadows); Cvar_RegisterVariable (&r_wateralpha); Cvar_SetCallback (&r_wateralpha, R_SetWateralpha_f); Cvar_RegisterVariable (&r_dynamic); Cvar_RegisterVariable (&r_novis); Cvar_SetCallback (&r_novis, R_VisChanged); Cvar_RegisterVariable (&r_speeds); Cvar_RegisterVariable (&r_pos); Cvar_RegisterVariable (&gl_finish); Cvar_RegisterVariable (&gl_clear); Cvar_RegisterVariable (&gl_cull); Cvar_RegisterVariable (&gl_smoothmodels); Cvar_RegisterVariable (&gl_affinemodels); Cvar_RegisterVariable (&gl_polyblend); Cvar_RegisterVariable (&gl_flashblend); Cvar_RegisterVariable (&gl_playermip); Cvar_RegisterVariable (&gl_nocolors); //johnfitz -- new cvars Cvar_RegisterVariable (&r_stereo); Cvar_RegisterVariable (&r_stereodepth); Cvar_RegisterVariable (&r_clearcolor); Cvar_SetCallback (&r_clearcolor, R_SetClearColor_f); Cvar_RegisterVariable (&r_waterquality); Cvar_RegisterVariable (&r_oldwater); Cvar_RegisterVariable (&r_waterwarp); Cvar_RegisterVariable (&r_drawflat); Cvar_RegisterVariable (&r_flatlightstyles); Cvar_RegisterVariable (&r_oldskyleaf); Cvar_SetCallback (&r_oldskyleaf, R_VisChanged); Cvar_RegisterVariable (&r_drawworld); Cvar_RegisterVariable (&r_showtris); Cvar_RegisterVariable (&r_showbboxes); Cvar_RegisterVariable (&gl_farclip); Cvar_RegisterVariable (&gl_fullbrights); Cvar_RegisterVariable (&gl_overbright); Cvar_SetCallback (&gl_fullbrights, GL_Fullbrights_f); Cvar_SetCallback (&gl_overbright, GL_Overbright_f); Cvar_RegisterVariable (&gl_overbright_models); Cvar_RegisterVariable (&r_lerpmodels); Cvar_RegisterVariable (&r_lerpmove); Cvar_RegisterVariable (&r_nolerp_list); Cvar_SetCallback (&r_nolerp_list, R_Model_ExtraFlags_List_f); Cvar_RegisterVariable (&r_noshadow_list); Cvar_SetCallback (&r_noshadow_list, R_Model_ExtraFlags_List_f); //johnfitz Cvar_RegisterVariable (&gl_zfix); // QuakeSpasm z-fighting fix Cvar_RegisterVariable (&r_lavaalpha); Cvar_RegisterVariable (&r_telealpha); Cvar_RegisterVariable (&r_slimealpha); Cvar_SetCallback (&r_lavaalpha, R_SetLavaalpha_f); Cvar_SetCallback (&r_telealpha, R_SetTelealpha_f); Cvar_SetCallback (&r_slimealpha, R_SetSlimealpha_f); R_InitParticles (); R_SetClearColor_f (&r_clearcolor); //johnfitz Sky_Init (); //johnfitz Fog_Init (); //johnfitz } /* =============== R_TranslatePlayerSkin -- johnfitz -- rewritten. also, only handles new colors, not new skins =============== */ void R_TranslatePlayerSkin (int playernum) { int top, bottom; top = (cl.scores[playernum].colors & 0xf0)>>4; bottom = cl.scores[playernum].colors &15; //FIXME: if gl_nocolors is on, then turned off, the textures may be out of sync with the scoreboard colors. if (!gl_nocolors.value) if (playertextures[playernum]) TexMgr_ReloadImage (playertextures[playernum], top, bottom); } /* =============== R_TranslateNewPlayerSkin -- johnfitz -- split off of TranslatePlayerSkin -- this is called when the skin or model actually changes, instead of just new colors added bug fix from bengt jardup =============== */ void R_TranslateNewPlayerSkin (int playernum) { char name[64]; byte *pixels; aliashdr_t *paliashdr; int skinnum; //get correct texture pixels currententity = &cl_entities[1+playernum]; if (!currententity->model || currententity->model->type != mod_alias) return; paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); skinnum = currententity->skinnum; //TODO: move these tests to the place where skinnum gets received from the server if (skinnum < 0 || skinnum >= paliashdr->numskins) { Con_DPrintf("(%d): Invalid player skin #%d\n", playernum, skinnum); skinnum = 0; } pixels = (byte *)paliashdr + paliashdr->texels[skinnum]; // This is not a persistent place! //upload new image q_snprintf(name, sizeof(name), "player_%i", playernum); playertextures[playernum] = TexMgr_LoadImage (currententity->model, name, paliashdr->skinwidth, paliashdr->skinheight, SRC_INDEXED, pixels, paliashdr->gltextures[skinnum][0]->source_file, paliashdr->gltextures[skinnum][0]->source_offset, TEXPREF_PAD | TEXPREF_OVERWRITE); //now recolor it R_TranslatePlayerSkin (playernum); } /* =============== R_NewGame -- johnfitz -- handle a game switch =============== */ void R_NewGame (void) { int i; //clear playertexture pointers (the textures themselves were freed by texmgr_newgame) for (i=0; i<MAX_SCOREBOARD; i++) playertextures[i] = NULL; } /* ============= R_ParseWorldspawn called at map load ============= */ static void R_ParseWorldspawn (void) { char key[128], value[4096]; const char *data; map_wateralpha = r_wateralpha.value; map_lavaalpha = r_lavaalpha.value; map_telealpha = r_telealpha.value; map_slimealpha = r_slimealpha.value; data = COM_Parse(cl.worldmodel->entities); if (!data) return; // error if (com_token[0] != '{') return; // error while (1) { data = COM_Parse(data); if (!data) return; // error if (com_token[0] == '}') break; // end of worldspawn if (com_token[0] == '_') strcpy(key, com_token + 1); else strcpy(key, com_token); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; data = COM_Parse(data); if (!data) return; // error strcpy(value, com_token); if (!strcmp("wateralpha", key)) map_wateralpha = atof(value); if (!strcmp("lavaalpha", key)) map_lavaalpha = atof(value); if (!strcmp("telealpha", key)) map_telealpha = atof(value); if (!strcmp("slimealpha", key)) map_slimealpha = atof(value); } } /* =============== R_NewMap =============== */ void R_NewMap (void) { int i; for (i=0 ; i<256 ; i++) d_lightstylevalue[i] = 264; // normal light value // clear out efrags in case the level hasn't been reloaded // FIXME: is this one short? for (i=0 ; i<cl.worldmodel->numleafs ; i++) cl.worldmodel->leafs[i].efrags = NULL; r_viewleaf = NULL; R_ClearParticles (); GL_BuildLightmaps (); GL_BuildBModelVertexBuffer (); //ericw -- no longer load alias models into a VBO here, it's done in Mod_LoadAliasModel r_framecount = 0; //johnfitz -- paranoid? r_visframecount = 0; //johnfitz -- paranoid? Sky_NewMap (); //johnfitz -- skybox in worldspawn Fog_NewMap (); //johnfitz -- global fog in worldspawn R_ParseWorldspawn (); //ericw -- wateralpha, lavaalpha, telealpha, slimealpha in worldspawn load_subdivide_size = gl_subdivide_size.value; //johnfitz -- is this the right place to set this? } /* ==================== R_TimeRefresh_f For program optimization ==================== */ void R_TimeRefresh_f (void) { int i; float start, stop, time; if (cls.state != ca_connected) { Con_Printf("Not connected to a server\n"); return; } start = Sys_DoubleTime (); for (i = 0; i < 128; i++) { GL_BeginRendering(&glx, &gly, &glwidth, &glheight); r_refdef.viewangles[1] = i/128.0*360.0; R_RenderView (); GL_EndRendering (); } glFinish (); stop = Sys_DoubleTime (); time = stop-start; Con_Printf ("%f seconds (%f fps)\n", time, 128/time); } void D_FlushCaches (void) { } static GLuint gl_programs[16]; static int gl_num_programs; static qboolean GL_CheckShader (GLuint shader) { GLint status; GL_GetShaderivFunc (shader, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { char infolog[1024]; memset(infolog, 0, sizeof(infolog)); GL_GetShaderInfoLogFunc (shader, sizeof(infolog), NULL, infolog); Con_Warning ("GLSL program failed to compile: %s", infolog); return false; } return true; } static qboolean GL_CheckProgram (GLuint program) { GLint status; GL_GetProgramivFunc (program, GL_LINK_STATUS, &status); if (status != GL_TRUE) { char infolog[1024]; memset(infolog, 0, sizeof(infolog)); GL_GetProgramInfoLogFunc (program, sizeof(infolog), NULL, infolog); Con_Warning ("GLSL program failed to link: %s", infolog); return false; } return true; } /* ============= GL_GetUniformLocation ============= */ GLint GL_GetUniformLocation (GLuint *programPtr, const char *name) { GLint location; if (!programPtr) return -1; location = GL_GetUniformLocationFunc(*programPtr, name); if (location == -1) { Con_Warning("GL_GetUniformLocationFunc %s failed\n", name); *programPtr = 0; } return location; } /* ==================== GL_CreateProgram Compiles and returns GLSL program. ==================== */ GLuint GL_CreateProgram (const GLchar *vertSource, const GLchar *fragSource, int numbindings, const glsl_attrib_binding_t *bindings) { int i; GLuint program, vertShader, fragShader; if (!gl_glsl_able) return 0; vertShader = GL_CreateShaderFunc (GL_VERTEX_SHADER); GL_ShaderSourceFunc (vertShader, 1, &vertSource, NULL); GL_CompileShaderFunc (vertShader); if (!GL_CheckShader (vertShader)) { GL_DeleteShaderFunc (vertShader); return 0; } fragShader = GL_CreateShaderFunc (GL_FRAGMENT_SHADER); GL_ShaderSourceFunc (fragShader, 1, &fragSource, NULL); GL_CompileShaderFunc (fragShader); if (!GL_CheckShader (fragShader)) { GL_DeleteShaderFunc (vertShader); GL_DeleteShaderFunc (fragShader); return 0; } program = GL_CreateProgramFunc (); GL_AttachShaderFunc (program, vertShader); GL_DeleteShaderFunc (vertShader); GL_AttachShaderFunc (program, fragShader); GL_DeleteShaderFunc (fragShader); for (i = 0; i < numbindings; i++) { GL_BindAttribLocationFunc (program, bindings[i].attrib, bindings[i].name); } GL_LinkProgramFunc (program); if (!GL_CheckProgram (program)) { GL_DeleteProgramFunc (program); return 0; } else { if (gl_num_programs == (sizeof(gl_programs)/sizeof(GLuint))) Host_Error ("gl_programs overflow"); gl_programs[gl_num_programs] = program; gl_num_programs++; return program; } } /* ==================== R_DeleteShaders Deletes any GLSL programs that have been created. ==================== */ void R_DeleteShaders (void) { int i; if (!gl_glsl_able) return; for (i = 0; i < gl_num_programs; i++) { GL_DeleteProgramFunc (gl_programs[i]); gl_programs[i] = 0; } gl_num_programs = 0; } GLuint current_array_buffer, current_element_array_buffer; /* ==================== GL_BindBuffer glBindBuffer wrapper ==================== */ void GL_BindBuffer (GLenum target, GLuint buffer) { GLuint *cache; if (!gl_vbo_able) return; switch (target) { case GL_ARRAY_BUFFER: cache = ¤t_array_buffer; break; case GL_ELEMENT_ARRAY_BUFFER: cache = ¤t_element_array_buffer; break; default: Host_Error("GL_BindBuffer: unsupported target %d", (int)target); return; } if (*cache != buffer) { *cache = buffer; GL_BindBufferFunc (target, *cache); } } /* ==================== GL_ClearBufferBindings This must be called if you do anything that could make the cached bindings invalid (e.g. manually binding, destroying the context). ==================== */ void GL_ClearBufferBindings () { if (!gl_vbo_able) return; current_array_buffer = 0; current_element_array_buffer = 0; GL_BindBufferFunc (GL_ARRAY_BUFFER, 0); GL_BindBufferFunc (GL_ELEMENT_ARRAY_BUFFER, 0); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/anorm_dots.h����������������������������������������������������������������0000644�0000000�0000000�00000063700�12407762022�016045� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * anorm_dots.h * * Copyright (C) 1996-1997 Id Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT 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. */ // 0 { 1.23, 1.30, 1.47, 1.35, 1.56, 1.71, 1.37, 1.38, 1.59, 1.60, 1.79, 1.97, 1.88, 1.92, 1.79, 1.02, 0.93, 1.07, 0.82, 0.87, 0.88, 0.94, 0.96, 1.14, 1.11, 0.82, 0.83, 0.89, 0.89, 0.86, 0.94, 0.91, 1.00, 1.21, 0.98, 1.48, 1.30, 1.57, 0.96, 1.07, 1.14, 1.60, 1.61, 1.40, 1.37, 1.72, 1.78, 1.79, 1.93, 1.99, 1.90, 1.68, 1.71, 1.86, 1.60, 1.68, 1.78, 1.86, 1.93, 1.99, 1.97, 1.44, 1.22, 1.49, 0.93, 0.99, 0.99, 1.23, 1.22, 1.44, 1.49, 0.89, 0.89, 0.97, 0.91, 0.98, 1.19, 0.82, 0.76, 0.82, 0.71, 0.72, 0.73, 0.76, 0.79, 0.86, 0.83, 0.72, 0.76, 0.76, 0.89, 0.82, 0.89, 0.82, 0.89, 0.91, 0.83, 0.96, 1.14, 0.97, 1.40, 1.19, 0.98, 0.94, 1.00, 1.07, 1.37, 1.21, 1.48, 1.30, 1.57, 1.61, 1.37, 0.86, 0.83, 0.91, 0.82, 0.82, 0.88, 0.89, 0.96, 1.14, 0.98, 0.87, 0.93, 0.94, 1.02, 1.30, 1.07, 1.35, 1.38, 1.11, 1.56, 1.92, 1.79, 1.79, 1.59, 1.60, 1.72, 1.90, 1.79, 0.80, 0.85, 0.79, 0.93, 0.80, 0.85, 0.77, 0.74, 0.72, 0.77, 0.74, 0.72, 0.70, 0.70, 0.71, 0.76, 0.73, 0.79, 0.79, 0.73, 0.76, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 1 { 1.26, 1.26, 1.48, 1.23, 1.50, 1.71, 1.14, 1.19, 1.38, 1.46, 1.64, 1.94, 1.87, 1.84, 1.71, 1.02, 0.92, 1.00, 0.79, 0.85, 0.84, 0.91, 0.90, 0.98, 0.99, 0.77, 0.77, 0.83, 0.82, 0.79, 0.86, 0.84, 0.92, 0.99, 0.91, 1.24, 1.03, 1.33, 0.88, 0.94, 0.97, 1.41, 1.39, 1.18, 1.11, 1.51, 1.61, 1.59, 1.80, 1.91, 1.76, 1.54, 1.65, 1.76, 1.70, 1.70, 1.85, 1.85, 1.97, 1.99, 1.93, 1.28, 1.09, 1.39, 0.92, 0.97, 0.99, 1.18, 1.26, 1.52, 1.48, 0.83, 0.85, 0.90, 0.88, 0.93, 1.00, 0.77, 0.73, 0.78, 0.72, 0.71, 0.74, 0.75, 0.79, 0.86, 0.81, 0.75, 0.81, 0.79, 0.96, 0.88, 0.94, 0.86, 0.93, 0.92, 0.85, 1.08, 1.33, 1.05, 1.55, 1.31, 1.01, 1.05, 1.27, 1.31, 1.60, 1.47, 1.70, 1.54, 1.76, 1.76, 1.57, 0.93, 0.90, 0.99, 0.88, 0.88, 0.95, 0.97, 1.11, 1.39, 1.20, 0.92, 0.97, 1.01, 1.10, 1.39, 1.22, 1.51, 1.58, 1.32, 1.64, 1.97, 1.85, 1.91, 1.77, 1.74, 1.88, 1.99, 1.91, 0.79, 0.86, 0.80, 0.94, 0.84, 0.88, 0.74, 0.74, 0.71, 0.82, 0.77, 0.76, 0.70, 0.73, 0.72, 0.73, 0.70, 0.74, 0.85, 0.77, 0.82, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 2 { 1.34, 1.27, 1.53, 1.17, 1.46, 1.71, 0.98, 1.05, 1.20, 1.34, 1.48, 1.86, 1.82, 1.71, 1.62, 1.09, 0.94, 0.99, 0.79, 0.85, 0.82, 0.90, 0.87, 0.93, 0.96, 0.76, 0.74, 0.79, 0.76, 0.74, 0.79, 0.78, 0.85, 0.92, 0.85, 1.00, 0.93, 1.06, 0.81, 0.86, 0.89, 1.16, 1.12, 0.97, 0.95, 1.28, 1.38, 1.35, 1.60, 1.77, 1.57, 1.33, 1.50, 1.58, 1.69, 1.63, 1.82, 1.74, 1.91, 1.92, 1.80, 1.04, 0.97, 1.21, 0.90, 0.93, 0.97, 1.05, 1.21, 1.48, 1.37, 0.77, 0.80, 0.84, 0.85, 0.88, 0.92, 0.73, 0.71, 0.74, 0.74, 0.71, 0.75, 0.73, 0.79, 0.84, 0.78, 0.79, 0.86, 0.81, 1.05, 0.94, 0.99, 0.90, 0.95, 0.92, 0.86, 1.24, 1.44, 1.14, 1.59, 1.34, 1.02, 1.27, 1.50, 1.49, 1.80, 1.69, 1.86, 1.72, 1.87, 1.80, 1.69, 1.00, 0.98, 1.23, 0.95, 0.96, 1.09, 1.16, 1.37, 1.63, 1.46, 0.99, 1.10, 1.25, 1.24, 1.51, 1.41, 1.67, 1.77, 1.55, 1.72, 1.95, 1.89, 1.98, 1.91, 1.86, 1.97, 1.99, 1.94, 0.81, 0.89, 0.85, 0.98, 0.90, 0.94, 0.75, 0.78, 0.73, 0.89, 0.83, 0.82, 0.72, 0.77, 0.76, 0.72, 0.70, 0.71, 0.91, 0.83, 0.89, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 3 { 1.46, 1.34, 1.60, 1.16, 1.46, 1.71, 0.94, 0.99, 1.05, 1.26, 1.33, 1.74, 1.76, 1.57, 1.54, 1.23, 0.98, 1.05, 0.83, 0.89, 0.84, 0.92, 0.87, 0.91, 0.96, 0.78, 0.74, 0.79, 0.72, 0.72, 0.75, 0.76, 0.80, 0.88, 0.83, 0.94, 0.87, 0.95, 0.76, 0.80, 0.82, 0.97, 0.96, 0.89, 0.88, 1.08, 1.11, 1.10, 1.37, 1.59, 1.37, 1.07, 1.27, 1.34, 1.57, 1.45, 1.69, 1.55, 1.77, 1.79, 1.60, 0.93, 0.90, 0.99, 0.86, 0.87, 0.93, 0.96, 1.07, 1.35, 1.18, 0.73, 0.76, 0.77, 0.81, 0.82, 0.85, 0.70, 0.71, 0.72, 0.78, 0.73, 0.77, 0.73, 0.79, 0.82, 0.76, 0.83, 0.90, 0.84, 1.18, 0.98, 1.03, 0.92, 0.95, 0.90, 0.86, 1.32, 1.45, 1.15, 1.53, 1.27, 0.99, 1.42, 1.65, 1.58, 1.93, 1.83, 1.94, 1.81, 1.88, 1.74, 1.70, 1.19, 1.17, 1.44, 1.11, 1.15, 1.36, 1.41, 1.61, 1.81, 1.67, 1.22, 1.34, 1.50, 1.42, 1.65, 1.61, 1.82, 1.91, 1.75, 1.80, 1.89, 1.89, 1.98, 1.99, 1.94, 1.98, 1.92, 1.87, 0.86, 0.95, 0.92, 1.14, 0.98, 1.03, 0.79, 0.84, 0.77, 0.97, 0.90, 0.89, 0.76, 0.82, 0.82, 0.74, 0.72, 0.71, 0.98, 0.89, 0.97, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 4 { 1.60, 1.44, 1.68, 1.22, 1.49, 1.71, 0.93, 0.99, 0.99, 1.23, 1.22, 1.60, 1.68, 1.44, 1.49, 1.40, 1.14, 1.19, 0.89, 0.96, 0.89, 0.97, 0.89, 0.91, 0.98, 0.82, 0.76, 0.82, 0.71, 0.72, 0.73, 0.76, 0.79, 0.86, 0.83, 0.91, 0.83, 0.89, 0.72, 0.76, 0.76, 0.89, 0.89, 0.82, 0.82, 0.98, 0.96, 0.97, 1.14, 1.40, 1.19, 0.94, 1.00, 1.07, 1.37, 1.21, 1.48, 1.30, 1.57, 1.61, 1.37, 0.86, 0.83, 0.91, 0.82, 0.82, 0.88, 0.89, 0.96, 1.14, 0.98, 0.70, 0.72, 0.73, 0.77, 0.76, 0.79, 0.70, 0.72, 0.71, 0.82, 0.77, 0.80, 0.74, 0.79, 0.80, 0.74, 0.87, 0.93, 0.85, 1.23, 1.02, 1.02, 0.93, 0.93, 0.87, 0.85, 1.30, 1.35, 1.07, 1.38, 1.11, 0.94, 1.47, 1.71, 1.56, 1.97, 1.88, 1.92, 1.79, 1.79, 1.59, 1.60, 1.30, 1.35, 1.56, 1.37, 1.38, 1.59, 1.60, 1.79, 1.92, 1.79, 1.48, 1.57, 1.72, 1.61, 1.78, 1.79, 1.93, 1.99, 1.90, 1.86, 1.78, 1.86, 1.93, 1.99, 1.97, 1.90, 1.79, 1.72, 0.94, 1.07, 1.00, 1.37, 1.21, 1.30, 0.86, 0.91, 0.83, 1.14, 0.98, 0.96, 0.82, 0.88, 0.89, 0.79, 0.76, 0.73, 1.07, 0.94, 1.11, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 5 { 1.74, 1.57, 1.76, 1.33, 1.54, 1.71, 0.94, 1.05, 0.99, 1.26, 1.16, 1.46, 1.60, 1.34, 1.46, 1.59, 1.37, 1.37, 0.97, 1.11, 0.96, 1.10, 0.95, 0.94, 1.08, 0.89, 0.82, 0.88, 0.72, 0.76, 0.75, 0.80, 0.80, 0.88, 0.87, 0.91, 0.83, 0.87, 0.72, 0.76, 0.74, 0.83, 0.84, 0.78, 0.79, 0.96, 0.89, 0.92, 0.98, 1.23, 1.05, 0.86, 0.92, 0.95, 1.11, 0.98, 1.22, 1.03, 1.34, 1.42, 1.14, 0.79, 0.77, 0.84, 0.78, 0.76, 0.82, 0.82, 0.89, 0.97, 0.90, 0.70, 0.71, 0.71, 0.73, 0.72, 0.74, 0.73, 0.76, 0.72, 0.86, 0.81, 0.82, 0.76, 0.79, 0.77, 0.73, 0.90, 0.95, 0.86, 1.18, 1.03, 0.98, 0.92, 0.90, 0.83, 0.84, 1.19, 1.17, 0.98, 1.15, 0.97, 0.89, 1.42, 1.65, 1.44, 1.93, 1.83, 1.81, 1.67, 1.61, 1.36, 1.41, 1.32, 1.45, 1.58, 1.57, 1.53, 1.74, 1.70, 1.88, 1.94, 1.81, 1.69, 1.77, 1.87, 1.79, 1.89, 1.92, 1.98, 1.99, 1.98, 1.89, 1.65, 1.80, 1.82, 1.91, 1.94, 1.75, 1.61, 1.50, 1.07, 1.34, 1.27, 1.60, 1.45, 1.55, 0.93, 0.99, 0.90, 1.35, 1.18, 1.07, 0.87, 0.93, 0.96, 0.85, 0.82, 0.77, 1.15, 0.99, 1.27, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 6 { 1.86, 1.71, 1.82, 1.48, 1.62, 1.71, 0.98, 1.20, 1.05, 1.34, 1.17, 1.34, 1.53, 1.27, 1.46, 1.77, 1.60, 1.57, 1.16, 1.38, 1.12, 1.35, 1.06, 1.00, 1.28, 0.97, 0.89, 0.95, 0.76, 0.81, 0.79, 0.86, 0.85, 0.92, 0.93, 0.93, 0.85, 0.87, 0.74, 0.78, 0.74, 0.79, 0.82, 0.76, 0.79, 0.96, 0.85, 0.90, 0.94, 1.09, 0.99, 0.81, 0.85, 0.89, 0.95, 0.90, 0.99, 0.94, 1.10, 1.24, 0.98, 0.75, 0.73, 0.78, 0.74, 0.72, 0.77, 0.76, 0.82, 0.89, 0.83, 0.73, 0.71, 0.71, 0.71, 0.70, 0.72, 0.77, 0.80, 0.74, 0.90, 0.85, 0.84, 0.78, 0.79, 0.75, 0.73, 0.92, 0.95, 0.86, 1.05, 0.99, 0.94, 0.90, 0.86, 0.79, 0.81, 1.00, 0.98, 0.91, 0.96, 0.89, 0.83, 1.27, 1.50, 1.23, 1.80, 1.69, 1.63, 1.46, 1.37, 1.09, 1.16, 1.24, 1.44, 1.49, 1.69, 1.59, 1.80, 1.69, 1.87, 1.86, 1.72, 1.82, 1.91, 1.94, 1.92, 1.95, 1.99, 1.98, 1.91, 1.97, 1.89, 1.51, 1.72, 1.67, 1.77, 1.86, 1.55, 1.41, 1.25, 1.33, 1.58, 1.50, 1.80, 1.63, 1.74, 1.04, 1.21, 0.97, 1.48, 1.37, 1.21, 0.93, 0.97, 1.05, 0.92, 0.88, 0.84, 1.14, 1.02, 1.34, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 7 { 1.94, 1.84, 1.87, 1.64, 1.71, 1.71, 1.14, 1.38, 1.19, 1.46, 1.23, 1.26, 1.48, 1.26, 1.50, 1.91, 1.80, 1.76, 1.41, 1.61, 1.39, 1.59, 1.33, 1.24, 1.51, 1.18, 0.97, 1.11, 0.82, 0.88, 0.86, 0.94, 0.92, 0.99, 1.03, 0.98, 0.91, 0.90, 0.79, 0.84, 0.77, 0.79, 0.84, 0.77, 0.83, 0.99, 0.85, 0.91, 0.92, 1.02, 1.00, 0.79, 0.80, 0.86, 0.88, 0.84, 0.92, 0.88, 0.97, 1.10, 0.94, 0.74, 0.71, 0.74, 0.72, 0.70, 0.73, 0.72, 0.76, 0.82, 0.77, 0.77, 0.73, 0.74, 0.71, 0.70, 0.73, 0.83, 0.85, 0.78, 0.92, 0.88, 0.86, 0.81, 0.79, 0.74, 0.75, 0.92, 0.93, 0.85, 0.96, 0.94, 0.88, 0.86, 0.81, 0.75, 0.79, 0.93, 0.90, 0.85, 0.88, 0.82, 0.77, 1.05, 1.27, 0.99, 1.60, 1.47, 1.39, 1.20, 1.11, 0.95, 0.97, 1.08, 1.33, 1.31, 1.70, 1.55, 1.76, 1.57, 1.76, 1.70, 1.54, 1.85, 1.97, 1.91, 1.99, 1.97, 1.99, 1.91, 1.77, 1.88, 1.85, 1.39, 1.64, 1.51, 1.58, 1.74, 1.32, 1.22, 1.01, 1.54, 1.76, 1.65, 1.93, 1.70, 1.85, 1.28, 1.39, 1.09, 1.52, 1.48, 1.26, 0.97, 0.99, 1.18, 1.00, 0.93, 0.90, 1.05, 1.01, 1.31, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 8 { 1.97, 1.92, 1.88, 1.79, 1.79, 1.71, 1.37, 1.59, 1.38, 1.60, 1.35, 1.23, 1.47, 1.30, 1.56, 1.99, 1.93, 1.90, 1.60, 1.78, 1.61, 1.79, 1.57, 1.48, 1.72, 1.40, 1.14, 1.37, 0.89, 0.96, 0.94, 1.07, 1.00, 1.21, 1.30, 1.14, 0.98, 0.96, 0.86, 0.91, 0.83, 0.82, 0.88, 0.82, 0.89, 1.11, 0.87, 0.94, 0.93, 1.02, 1.07, 0.80, 0.79, 0.85, 0.82, 0.80, 0.87, 0.85, 0.93, 1.02, 0.93, 0.77, 0.72, 0.74, 0.71, 0.70, 0.70, 0.71, 0.72, 0.77, 0.74, 0.82, 0.76, 0.79, 0.72, 0.73, 0.76, 0.89, 0.89, 0.82, 0.93, 0.91, 0.86, 0.83, 0.79, 0.73, 0.76, 0.91, 0.89, 0.83, 0.89, 0.89, 0.82, 0.82, 0.76, 0.72, 0.76, 0.86, 0.83, 0.79, 0.82, 0.76, 0.73, 0.94, 1.00, 0.91, 1.37, 1.21, 1.14, 0.98, 0.96, 0.88, 0.89, 0.96, 1.14, 1.07, 1.60, 1.40, 1.61, 1.37, 1.57, 1.48, 1.30, 1.78, 1.93, 1.79, 1.99, 1.92, 1.90, 1.79, 1.59, 1.72, 1.79, 1.30, 1.56, 1.35, 1.38, 1.60, 1.11, 1.07, 0.94, 1.68, 1.86, 1.71, 1.97, 1.68, 1.86, 1.44, 1.49, 1.22, 1.44, 1.49, 1.22, 0.99, 0.99, 1.23, 1.19, 0.98, 0.97, 0.97, 0.98, 1.19, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 9 { 1.94, 1.97, 1.87, 1.91, 1.85, 1.71, 1.60, 1.77, 1.58, 1.74, 1.51, 1.26, 1.48, 1.39, 1.64, 1.99, 1.97, 1.99, 1.70, 1.85, 1.76, 1.91, 1.76, 1.70, 1.88, 1.55, 1.33, 1.57, 0.96, 1.08, 1.05, 1.31, 1.27, 1.47, 1.54, 1.39, 1.20, 1.11, 0.93, 0.99, 0.90, 0.88, 0.95, 0.88, 0.97, 1.32, 0.92, 1.01, 0.97, 1.10, 1.22, 0.84, 0.80, 0.88, 0.79, 0.79, 0.85, 0.86, 0.92, 1.02, 0.94, 0.82, 0.76, 0.77, 0.72, 0.73, 0.70, 0.72, 0.71, 0.74, 0.74, 0.88, 0.81, 0.85, 0.75, 0.77, 0.82, 0.94, 0.93, 0.86, 0.92, 0.92, 0.86, 0.85, 0.79, 0.74, 0.79, 0.88, 0.85, 0.81, 0.82, 0.83, 0.77, 0.78, 0.73, 0.71, 0.75, 0.79, 0.77, 0.74, 0.77, 0.73, 0.70, 0.86, 0.92, 0.84, 1.14, 0.99, 0.98, 0.91, 0.90, 0.84, 0.83, 0.88, 0.97, 0.94, 1.41, 1.18, 1.39, 1.11, 1.33, 1.24, 1.03, 1.61, 1.80, 1.59, 1.91, 1.84, 1.76, 1.64, 1.38, 1.51, 1.71, 1.26, 1.50, 1.23, 1.19, 1.46, 0.99, 1.00, 0.91, 1.70, 1.85, 1.65, 1.93, 1.54, 1.76, 1.52, 1.48, 1.26, 1.28, 1.39, 1.09, 0.99, 0.97, 1.18, 1.31, 1.01, 1.05, 0.90, 0.93, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 10 { 1.86, 1.95, 1.82, 1.98, 1.89, 1.71, 1.80, 1.91, 1.77, 1.86, 1.67, 1.34, 1.53, 1.51, 1.72, 1.92, 1.91, 1.99, 1.69, 1.82, 1.80, 1.94, 1.87, 1.86, 1.97, 1.59, 1.44, 1.69, 1.05, 1.24, 1.27, 1.49, 1.50, 1.69, 1.72, 1.63, 1.46, 1.37, 1.00, 1.23, 0.98, 0.95, 1.09, 0.96, 1.16, 1.55, 0.99, 1.25, 1.10, 1.24, 1.41, 0.90, 0.85, 0.94, 0.79, 0.81, 0.85, 0.89, 0.94, 1.09, 0.98, 0.89, 0.82, 0.83, 0.74, 0.77, 0.72, 0.76, 0.73, 0.75, 0.78, 0.94, 0.86, 0.91, 0.79, 0.83, 0.89, 0.99, 0.95, 0.90, 0.90, 0.92, 0.84, 0.86, 0.79, 0.75, 0.81, 0.85, 0.80, 0.78, 0.76, 0.77, 0.73, 0.74, 0.71, 0.71, 0.73, 0.74, 0.74, 0.71, 0.76, 0.72, 0.70, 0.79, 0.85, 0.78, 0.98, 0.92, 0.93, 0.85, 0.87, 0.82, 0.79, 0.81, 0.89, 0.86, 1.16, 0.97, 1.12, 0.95, 1.06, 1.00, 0.93, 1.38, 1.60, 1.35, 1.77, 1.71, 1.57, 1.48, 1.20, 1.28, 1.62, 1.27, 1.46, 1.17, 1.05, 1.34, 0.96, 0.99, 0.90, 1.63, 1.74, 1.50, 1.80, 1.33, 1.58, 1.48, 1.37, 1.21, 1.04, 1.21, 0.97, 0.97, 0.93, 1.05, 1.34, 1.02, 1.14, 0.84, 0.88, 0.92, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 11 { 1.74, 1.89, 1.76, 1.98, 1.89, 1.71, 1.93, 1.99, 1.91, 1.94, 1.82, 1.46, 1.60, 1.65, 1.80, 1.79, 1.77, 1.92, 1.57, 1.69, 1.74, 1.87, 1.88, 1.94, 1.98, 1.53, 1.45, 1.70, 1.18, 1.32, 1.42, 1.58, 1.65, 1.83, 1.81, 1.81, 1.67, 1.61, 1.19, 1.44, 1.17, 1.11, 1.36, 1.15, 1.41, 1.75, 1.22, 1.50, 1.34, 1.42, 1.61, 0.98, 0.92, 1.03, 0.83, 0.86, 0.89, 0.95, 0.98, 1.23, 1.14, 0.97, 0.89, 0.90, 0.78, 0.82, 0.76, 0.82, 0.77, 0.79, 0.84, 0.98, 0.90, 0.98, 0.83, 0.89, 0.97, 1.03, 0.95, 0.92, 0.86, 0.90, 0.82, 0.86, 0.79, 0.77, 0.84, 0.81, 0.76, 0.76, 0.72, 0.73, 0.70, 0.72, 0.71, 0.73, 0.73, 0.72, 0.74, 0.71, 0.78, 0.74, 0.72, 0.75, 0.80, 0.76, 0.94, 0.88, 0.91, 0.83, 0.87, 0.84, 0.79, 0.76, 0.82, 0.80, 0.97, 0.89, 0.96, 0.88, 0.95, 0.94, 0.87, 1.11, 1.37, 1.10, 1.59, 1.57, 1.37, 1.33, 1.05, 1.08, 1.54, 1.34, 1.46, 1.16, 0.99, 1.26, 0.96, 1.05, 0.92, 1.45, 1.55, 1.27, 1.60, 1.07, 1.34, 1.35, 1.18, 1.07, 0.93, 0.99, 0.90, 0.93, 0.87, 0.96, 1.27, 0.99, 1.15, 0.77, 0.82, 0.85, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 12 { 1.60, 1.78, 1.68, 1.93, 1.86, 1.71, 1.97, 1.99, 1.99, 1.97, 1.93, 1.60, 1.68, 1.78, 1.86, 1.61, 1.57, 1.79, 1.37, 1.48, 1.59, 1.72, 1.79, 1.92, 1.90, 1.38, 1.35, 1.60, 1.23, 1.30, 1.47, 1.56, 1.71, 1.88, 1.79, 1.92, 1.79, 1.79, 1.30, 1.56, 1.35, 1.37, 1.59, 1.38, 1.60, 1.90, 1.48, 1.72, 1.57, 1.61, 1.79, 1.21, 1.00, 1.30, 0.89, 0.94, 0.96, 1.07, 1.14, 1.40, 1.37, 1.14, 0.96, 0.98, 0.82, 0.88, 0.82, 0.89, 0.83, 0.86, 0.91, 1.02, 0.93, 1.07, 0.87, 0.94, 1.11, 1.02, 0.93, 0.93, 0.82, 0.87, 0.80, 0.85, 0.79, 0.80, 0.85, 0.77, 0.72, 0.74, 0.71, 0.70, 0.70, 0.71, 0.72, 0.77, 0.74, 0.72, 0.76, 0.73, 0.82, 0.79, 0.76, 0.73, 0.79, 0.76, 0.93, 0.86, 0.91, 0.83, 0.89, 0.89, 0.82, 0.72, 0.76, 0.76, 0.89, 0.82, 0.89, 0.82, 0.89, 0.91, 0.83, 0.96, 1.14, 0.97, 1.40, 1.44, 1.19, 1.22, 0.99, 0.98, 1.49, 1.44, 1.49, 1.22, 0.99, 1.23, 0.98, 1.19, 0.97, 1.21, 1.30, 1.00, 1.37, 0.94, 1.07, 1.14, 0.98, 0.96, 0.86, 0.91, 0.83, 0.88, 0.82, 0.89, 1.11, 0.94, 1.07, 0.73, 0.76, 0.79, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 13 { 1.46, 1.65, 1.60, 1.82, 1.80, 1.71, 1.93, 1.91, 1.99, 1.94, 1.98, 1.74, 1.76, 1.89, 1.89, 1.42, 1.34, 1.61, 1.11, 1.22, 1.36, 1.50, 1.61, 1.81, 1.75, 1.15, 1.17, 1.41, 1.18, 1.19, 1.42, 1.44, 1.65, 1.83, 1.67, 1.94, 1.81, 1.88, 1.32, 1.58, 1.45, 1.57, 1.74, 1.53, 1.70, 1.98, 1.69, 1.87, 1.77, 1.79, 1.92, 1.45, 1.27, 1.55, 0.97, 1.07, 1.11, 1.34, 1.37, 1.59, 1.60, 1.35, 1.07, 1.18, 0.86, 0.93, 0.87, 0.96, 0.90, 0.93, 0.99, 1.03, 0.95, 1.15, 0.90, 0.99, 1.27, 0.98, 0.90, 0.92, 0.78, 0.83, 0.77, 0.84, 0.79, 0.82, 0.86, 0.73, 0.71, 0.73, 0.72, 0.70, 0.73, 0.72, 0.76, 0.81, 0.76, 0.76, 0.82, 0.77, 0.89, 0.85, 0.82, 0.75, 0.80, 0.80, 0.94, 0.88, 0.94, 0.87, 0.95, 0.96, 0.88, 0.72, 0.74, 0.76, 0.83, 0.78, 0.84, 0.79, 0.87, 0.91, 0.83, 0.89, 0.98, 0.92, 1.23, 1.34, 1.05, 1.16, 0.99, 0.96, 1.46, 1.57, 1.54, 1.33, 1.05, 1.26, 1.08, 1.37, 1.10, 0.98, 1.03, 0.92, 1.14, 0.86, 0.95, 0.97, 0.90, 0.89, 0.79, 0.84, 0.77, 0.82, 0.76, 0.82, 0.97, 0.89, 0.98, 0.71, 0.72, 0.74, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 14 { 1.34, 1.51, 1.53, 1.67, 1.72, 1.71, 1.80, 1.77, 1.91, 1.86, 1.98, 1.86, 1.82, 1.95, 1.89, 1.24, 1.10, 1.41, 0.95, 0.99, 1.09, 1.25, 1.37, 1.63, 1.55, 0.96, 0.98, 1.16, 1.05, 1.00, 1.27, 1.23, 1.50, 1.69, 1.46, 1.86, 1.72, 1.87, 1.24, 1.49, 1.44, 1.69, 1.80, 1.59, 1.69, 1.97, 1.82, 1.94, 1.91, 1.92, 1.99, 1.63, 1.50, 1.74, 1.16, 1.33, 1.38, 1.58, 1.60, 1.77, 1.80, 1.48, 1.21, 1.37, 0.90, 0.97, 0.93, 1.05, 0.97, 1.04, 1.21, 0.99, 0.95, 1.14, 0.92, 1.02, 1.34, 0.94, 0.86, 0.90, 0.74, 0.79, 0.75, 0.81, 0.79, 0.84, 0.86, 0.71, 0.71, 0.73, 0.76, 0.73, 0.77, 0.74, 0.80, 0.85, 0.78, 0.81, 0.89, 0.84, 0.97, 0.92, 0.88, 0.79, 0.85, 0.86, 0.98, 0.92, 1.00, 0.93, 1.06, 1.12, 0.95, 0.74, 0.74, 0.78, 0.79, 0.76, 0.82, 0.79, 0.87, 0.93, 0.85, 0.85, 0.94, 0.90, 1.09, 1.27, 0.99, 1.17, 1.05, 0.96, 1.46, 1.71, 1.62, 1.48, 1.20, 1.34, 1.28, 1.57, 1.35, 0.90, 0.94, 0.85, 0.98, 0.81, 0.89, 0.89, 0.83, 0.82, 0.75, 0.78, 0.73, 0.77, 0.72, 0.76, 0.89, 0.83, 0.91, 0.71, 0.70, 0.72, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }, // 15 { 1.26, 1.39, 1.48, 1.51, 1.64, 1.71, 1.60, 1.58, 1.77, 1.74, 1.91, 1.94, 1.87, 1.97, 1.85, 1.10, 0.97, 1.22, 0.88, 0.92, 0.95, 1.01, 1.11, 1.39, 1.32, 0.88, 0.90, 0.97, 0.96, 0.93, 1.05, 0.99, 1.27, 1.47, 1.20, 1.70, 1.54, 1.76, 1.08, 1.31, 1.33, 1.70, 1.76, 1.55, 1.57, 1.88, 1.85, 1.91, 1.97, 1.99, 1.99, 1.70, 1.65, 1.85, 1.41, 1.54, 1.61, 1.76, 1.80, 1.91, 1.93, 1.52, 1.26, 1.48, 0.92, 0.99, 0.97, 1.18, 1.09, 1.28, 1.39, 0.94, 0.93, 1.05, 0.92, 1.01, 1.31, 0.88, 0.81, 0.86, 0.72, 0.75, 0.74, 0.79, 0.79, 0.86, 0.85, 0.71, 0.73, 0.75, 0.82, 0.77, 0.83, 0.78, 0.85, 0.88, 0.81, 0.88, 0.97, 0.90, 1.18, 1.00, 0.93, 0.86, 0.92, 0.94, 1.14, 0.99, 1.24, 1.03, 1.33, 1.39, 1.11, 0.79, 0.77, 0.84, 0.79, 0.77, 0.84, 0.83, 0.90, 0.98, 0.91, 0.85, 0.92, 0.91, 1.02, 1.26, 1.00, 1.23, 1.19, 0.99, 1.50, 1.84, 1.71, 1.64, 1.38, 1.46, 1.51, 1.76, 1.59, 0.84, 0.88, 0.80, 0.94, 0.79, 0.86, 0.82, 0.77, 0.76, 0.74, 0.74, 0.71, 0.73, 0.70, 0.72, 0.82, 0.77, 0.85, 0.74, 0.70, 0.73, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 } ����������������������������������������������������������������quakespasm-0.91.0/Quake/gl_fog.c��������������������������������������������������������������������0000644�0000000�0000000�00000020163�12625545642�015135� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //gl_fog.c -- global and volumetric fog #include "quakedef.h" //============================================================================== // // GLOBAL FOG // //============================================================================== #define DEFAULT_DENSITY 0.0 #define DEFAULT_GRAY 0.3 float fog_density; float fog_red; float fog_green; float fog_blue; float old_density; float old_red; float old_green; float old_blue; float fade_time; //duration of fade float fade_done; //time when fade will be done /* ============= Fog_Update update internal variables ============= */ void Fog_Update (float density, float red, float green, float blue, float time) { //save previous settings for fade if (time > 0) { //check for a fade in progress if (fade_done > cl.time) { float f; f = (fade_done - cl.time) / fade_time; old_density = f * old_density + (1.0 - f) * fog_density; old_red = f * old_red + (1.0 - f) * fog_red; old_green = f * old_green + (1.0 - f) * fog_green; old_blue = f * old_blue + (1.0 - f) * fog_blue; } else { old_density = fog_density; old_red = fog_red; old_green = fog_green; old_blue = fog_blue; } } fog_density = density; fog_red = red; fog_green = green; fog_blue = blue; fade_time = time; fade_done = cl.time + time; } /* ============= Fog_ParseServerMessage handle an SVC_FOG message from server ============= */ void Fog_ParseServerMessage (void) { float density, red, green, blue, time; density = MSG_ReadByte() / 255.0; red = MSG_ReadByte() / 255.0; green = MSG_ReadByte() / 255.0; blue = MSG_ReadByte() / 255.0; time = q_max(0.0, MSG_ReadShort() / 100.0); Fog_Update (density, red, green, blue, time); } /* ============= Fog_FogCommand_f handle the 'fog' console command ============= */ void Fog_FogCommand_f (void) { switch (Cmd_Argc()) { default: case 1: Con_Printf("usage:\n"); Con_Printf(" fog <density>\n"); Con_Printf(" fog <red> <green> <blue>\n"); Con_Printf(" fog <density> <red> <green> <blue>\n"); Con_Printf("current values:\n"); Con_Printf(" \"density\" is \"%f\"\n", fog_density); Con_Printf(" \"red\" is \"%f\"\n", fog_red); Con_Printf(" \"green\" is \"%f\"\n", fog_green); Con_Printf(" \"blue\" is \"%f\"\n", fog_blue); break; case 2: Fog_Update(q_max(0.0, atof(Cmd_Argv(1))), fog_red, fog_green, fog_blue, 0.0); break; case 3: //TEST Fog_Update(q_max(0.0, atof(Cmd_Argv(1))), fog_red, fog_green, fog_blue, atof(Cmd_Argv(2))); break; case 4: Fog_Update(fog_density, CLAMP(0.0, atof(Cmd_Argv(1)), 1.0), CLAMP(0.0, atof(Cmd_Argv(2)), 1.0), CLAMP(0.0, atof(Cmd_Argv(3)), 1.0), 0.0); break; case 5: Fog_Update(q_max(0.0, atof(Cmd_Argv(1))), CLAMP(0.0, atof(Cmd_Argv(2)), 1.0), CLAMP(0.0, atof(Cmd_Argv(3)), 1.0), CLAMP(0.0, atof(Cmd_Argv(4)), 1.0), 0.0); break; case 6: //TEST Fog_Update(q_max(0.0, atof(Cmd_Argv(1))), CLAMP(0.0, atof(Cmd_Argv(2)), 1.0), CLAMP(0.0, atof(Cmd_Argv(3)), 1.0), CLAMP(0.0, atof(Cmd_Argv(4)), 1.0), atof(Cmd_Argv(5))); break; } } /* ============= Fog_ParseWorldspawn called at map load ============= */ void Fog_ParseWorldspawn (void) { char key[128], value[4096]; const char *data; //initially no fog fog_density = DEFAULT_DENSITY; fog_red = DEFAULT_GRAY; fog_green = DEFAULT_GRAY; fog_blue = DEFAULT_GRAY; old_density = DEFAULT_DENSITY; old_red = DEFAULT_GRAY; old_green = DEFAULT_GRAY; old_blue = DEFAULT_GRAY; fade_time = 0.0; fade_done = 0.0; data = COM_Parse(cl.worldmodel->entities); if (!data) return; // error if (com_token[0] != '{') return; // error while (1) { data = COM_Parse(data); if (!data) return; // error if (com_token[0] == '}') break; // end of worldspawn if (com_token[0] == '_') strcpy(key, com_token + 1); else strcpy(key, com_token); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; data = COM_Parse(data); if (!data) return; // error strcpy(value, com_token); if (!strcmp("fog", key)) { sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue); } } } /* ============= Fog_GetColor calculates fog color for this frame, taking into account fade times ============= */ float *Fog_GetColor (void) { static float c[4]; float f; int i; if (fade_done > cl.time) { f = (fade_done - cl.time) / fade_time; c[0] = f * old_red + (1.0 - f) * fog_red; c[1] = f * old_green + (1.0 - f) * fog_green; c[2] = f * old_blue + (1.0 - f) * fog_blue; c[3] = 1.0; } else { c[0] = fog_red; c[1] = fog_green; c[2] = fog_blue; c[3] = 1.0; } //find closest 24-bit RGB value, so solid-colored sky can match the fog perfectly for (i=0;i<3;i++) c[i] = (float)(Q_rint(c[i] * 255)) / 255.0f; return c; } /* ============= Fog_GetDensity returns current density of fog ============= */ float Fog_GetDensity (void) { float f; if (fade_done > cl.time) { f = (fade_done - cl.time) / fade_time; return f * old_density + (1.0 - f) * fog_density; } else return fog_density; } /* ============= Fog_SetupFrame called at the beginning of each frame ============= */ void Fog_SetupFrame (void) { glFogfv(GL_FOG_COLOR, Fog_GetColor()); glFogf(GL_FOG_DENSITY, Fog_GetDensity() / 64.0); } /* ============= Fog_EnableGFog called before drawing stuff that should be fogged ============= */ void Fog_EnableGFog (void) { if (Fog_GetDensity() > 0) glEnable(GL_FOG); } /* ============= Fog_DisableGFog called after drawing stuff that should be fogged ============= */ void Fog_DisableGFog (void) { if (Fog_GetDensity() > 0) glDisable(GL_FOG); } /* ============= Fog_StartAdditive called before drawing stuff that is additive blended -- sets fog color to black ============= */ void Fog_StartAdditive (void) { vec3_t color = {0,0,0}; if (Fog_GetDensity() > 0) glFogfv(GL_FOG_COLOR, color); } /* ============= Fog_StopAdditive called after drawing stuff that is additive blended -- restores fog color ============= */ void Fog_StopAdditive (void) { if (Fog_GetDensity() > 0) glFogfv(GL_FOG_COLOR, Fog_GetColor()); } //============================================================================== // // VOLUMETRIC FOG // //============================================================================== cvar_t r_vfog = {"r_vfog", "1", CVAR_NONE}; void Fog_DrawVFog (void){} void Fog_MarkModels (void){} //============================================================================== // // INIT // //============================================================================== /* ============= Fog_NewMap called whenever a map is loaded ============= */ void Fog_NewMap (void) { Fog_ParseWorldspawn (); //for global fog Fog_MarkModels (); //for volumetric fog } /* ============= Fog_Init called when quake initializes ============= */ void Fog_Init (void) { Cmd_AddCommand ("fog",Fog_FogCommand_f); //Cvar_RegisterVariable (&r_vfog); //set up global fog fog_density = DEFAULT_DENSITY; fog_red = DEFAULT_GRAY; fog_green = DEFAULT_GRAY; fog_blue = DEFAULT_GRAY; Fog_SetupState (); } /* ============= Fog_SetupState ericw -- moved from Fog_Init, state that needs to be setup when a new context is created ============= */ void Fog_SetupState (void) { glFogi(GL_FOG_MODE, GL_EXP2); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_wipx.c������������������������������������������������������������������0000644�0000000�0000000�00000026523�12407762022�015532� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // net_wipx.c #include "q_stdinc.h" #include "arch_def.h" #include "net_sys.h" #include <wsipx.h> #include "quakedef.h" #include "net_defs.h" #include "net_wipx.h" extern cvar_t hostname; static sys_socket_t net_acceptsocket = INVALID_SOCKET; // socket for fielding new connections static sys_socket_t net_controlsocket; static struct sockaddr_ipx broadcastaddr; /* externs from net_wins.c: */ extern qboolean winsock_initialized; extern WSADATA winsockdata; extern const char *__WSAE_StrError (int); #define IPXSOCKETS 18 static sys_socket_t ipxsocket[IPXSOCKETS]; static int sequence[IPXSOCKETS]; //============================================================================= sys_socket_t WIPX_Init (void) { int i, err; char *colon; char buff[MAXHOSTNAMELEN]; struct qsockaddr addr; if (COM_CheckParm ("-noipx")) return INVALID_SOCKET; if (winsock_initialized == 0) { err = WSAStartup(MAKEWORD(1,1), &winsockdata); if (err != 0) { Con_SafePrintf("Winsock initialization failed (%s)\n", socketerror(err)); return INVALID_SOCKET; } } winsock_initialized++; for (i = 0; i < IPXSOCKETS; i++) ipxsocket[i] = 0; // determine my name & address if (gethostname(buff, MAXHOSTNAMELEN) != 0) { err = SOCKETERRNO; Con_SafePrintf("WIPX_Init: gethostname failed (%s)\n", socketerror(err)); } else { buff[MAXHOSTNAMELEN - 1] = 0; } if ((net_controlsocket = WIPX_OpenSocket(0)) == INVALID_SOCKET) { Con_SafePrintf("WIPX_Init: Unable to open control socket, IPX disabled\n"); if (--winsock_initialized == 0) WSACleanup (); return INVALID_SOCKET; } broadcastaddr.sa_family = AF_IPX; memset(broadcastaddr.sa_netnum, 0, 4); memset(broadcastaddr.sa_nodenum, 0xff, 6); broadcastaddr.sa_socket = htons((unsigned short)net_hostport); WIPX_GetSocketAddr (net_controlsocket, &addr); Q_strcpy(my_ipx_address, WIPX_AddrToString (&addr)); colon = Q_strrchr (my_ipx_address, ':'); if (colon) *colon = 0; Con_SafePrintf("IPX Initialized\n"); ipxAvailable = true; return net_controlsocket; } //============================================================================= void WIPX_Shutdown (void) { WIPX_Listen (false); WIPX_CloseSocket (net_controlsocket); if (--winsock_initialized == 0) WSACleanup (); } //============================================================================= void WIPX_Listen (qboolean state) { // enable listening if (state) { if (net_acceptsocket != INVALID_SOCKET) return; if ((net_acceptsocket = WIPX_OpenSocket (net_hostport)) == INVALID_SOCKET) Sys_Error ("WIPX_Listen: Unable to open accept socket"); return; } // disable listening if (net_acceptsocket == INVALID_SOCKET) return; WIPX_CloseSocket (net_acceptsocket); net_acceptsocket = INVALID_SOCKET; } //============================================================================= sys_socket_t WIPX_OpenSocket (int port) { int err; sys_socket_t handle, newsocket; struct sockaddr_ipx address; u_long _true = 1; for (handle = 0; handle < IPXSOCKETS; handle++) { if (ipxsocket[handle] == 0) break; } if (handle == IPXSOCKETS) { Con_SafePrintf("WIPX_OpenSocket: Out of free IPX handles.\n"); return INVALID_SOCKET; } if ((newsocket = socket (AF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == INVALID_SOCKET) { err = SOCKETERRNO; Con_SafePrintf("WIPX_OpenSocket: %s\n", socketerror(err)); return INVALID_SOCKET; } if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR) goto ErrorReturn; if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == SOCKET_ERROR) goto ErrorReturn; address.sa_family = AF_IPX; memset(address.sa_netnum, 0, 4); memset(address.sa_nodenum, 0, 6);; address.sa_socket = htons((unsigned short)port); if (bind (newsocket, (struct sockaddr *)&address, sizeof(address)) == 0) { ipxsocket[handle] = newsocket; sequence[handle] = 0; return handle; } if (ipxAvailable) { err = SOCKETERRNO; Sys_Error ("IPX bind failed (%s)", socketerror(err)); return INVALID_SOCKET; /* not reached */ } /* else: we are still in init phase, no need to error */ ErrorReturn: err = SOCKETERRNO; Con_SafePrintf("WIPX_OpenSocket: %s\n", socketerror(err)); closesocket (newsocket); return INVALID_SOCKET; } //============================================================================= int WIPX_CloseSocket (sys_socket_t handle) { sys_socket_t socketid = ipxsocket[handle]; int ret; ret = closesocket (socketid); ipxsocket[handle] = 0; return ret; } //============================================================================= int WIPX_Connect (sys_socket_t handle, struct qsockaddr *addr) { return 0; } //============================================================================= sys_socket_t WIPX_CheckNewConnections (void) { u_long available; if (net_acceptsocket == INVALID_SOCKET) return INVALID_SOCKET; if (ioctlsocket (ipxsocket[net_acceptsocket], FIONREAD, &available) == SOCKET_ERROR) { int err = SOCKETERRNO; Sys_Error ("WIPX: ioctlsocket (FIONREAD) failed (%s)", socketerror(err)); } if (available) return net_acceptsocket; return INVALID_SOCKET; } //============================================================================= static byte netpacketBuffer[NET_DATAGRAMSIZE + 4]; int WIPX_Read (sys_socket_t handle, byte *buf, int len, struct qsockaddr *addr) { socklen_t addrlen = sizeof(struct qsockaddr); sys_socket_t socketid = ipxsocket[handle]; int ret; ret = recvfrom (socketid, (char *)netpacketBuffer, len+4, 0, (struct sockaddr *)addr, &addrlen); if (ret == SOCKET_ERROR) { int err = SOCKETERRNO; if (err == NET_EWOULDBLOCK || err == NET_ECONNREFUSED) return 0; Con_SafePrintf ("WIPX_Read, recvfrom: %s\n", socketerror(err)); } if (ret < 4) return 0; // remove sequence number, it's only needed for DOS IPX ret -= 4; memcpy(buf, netpacketBuffer+4, ret); return ret; } //============================================================================= int WIPX_Broadcast (sys_socket_t handle, byte *buf, int len) { return WIPX_Write (handle, buf, len, (struct qsockaddr *)&broadcastaddr); } //============================================================================= int WIPX_Write (sys_socket_t handle, byte *buf, int len, struct qsockaddr *addr) { sys_socket_t socketid = ipxsocket[handle]; int ret; // build packet with sequence number memcpy(&netpacketBuffer[0], &sequence[handle], 4); sequence[handle]++; memcpy(&netpacketBuffer[4], buf, len); len += 4; ret = sendto (socketid, (char *)netpacketBuffer, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); if (ret == SOCKET_ERROR) { int err = SOCKETERRNO; if (err == NET_EWOULDBLOCK) return 0; Con_SafePrintf ("WIPX_Write, sendto: %s\n", socketerror(err)); } return ret; } //============================================================================= const char *WIPX_AddrToString (struct qsockaddr *addr) { static char buf[28]; sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u", ((struct sockaddr_ipx *)addr)->sa_netnum[0] & 0xff, ((struct sockaddr_ipx *)addr)->sa_netnum[1] & 0xff, ((struct sockaddr_ipx *)addr)->sa_netnum[2] & 0xff, ((struct sockaddr_ipx *)addr)->sa_netnum[3] & 0xff, ((struct sockaddr_ipx *)addr)->sa_nodenum[0] & 0xff, ((struct sockaddr_ipx *)addr)->sa_nodenum[1] & 0xff, ((struct sockaddr_ipx *)addr)->sa_nodenum[2] & 0xff, ((struct sockaddr_ipx *)addr)->sa_nodenum[3] & 0xff, ((struct sockaddr_ipx *)addr)->sa_nodenum[4] & 0xff, ((struct sockaddr_ipx *)addr)->sa_nodenum[5] & 0xff, ntohs(((struct sockaddr_ipx *)addr)->sa_socket) ); return buf; } //============================================================================= int WIPX_StringToAddr (const char *string, struct qsockaddr *addr) { int val; char buf[3]; buf[2] = 0; Q_memset(addr, 0, sizeof(struct qsockaddr)); addr->qsa_family = AF_IPX; #define DO(src,dest) do { \ buf[0] = string[src]; \ buf[1] = string[src + 1]; \ if (sscanf (buf, "%x", &val) != 1) \ return -1; \ ((struct sockaddr_ipx *)addr)->dest = val; \ } while (0) DO(0, sa_netnum[0]); DO(2, sa_netnum[1]); DO(4, sa_netnum[2]); DO(6, sa_netnum[3]); DO(9, sa_nodenum[0]); DO(11, sa_nodenum[1]); DO(13, sa_nodenum[2]); DO(15, sa_nodenum[3]); DO(17, sa_nodenum[4]); DO(19, sa_nodenum[5]); #undef DO sscanf (&string[22], "%u", &val); ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)val); return 0; } //============================================================================= int WIPX_GetSocketAddr (sys_socket_t handle, struct qsockaddr *addr) { sys_socket_t socketid = ipxsocket[handle]; socklen_t addrlen = sizeof(struct qsockaddr); Q_memset(addr, 0, sizeof(struct qsockaddr)); if (getsockname(socketid, (struct sockaddr *)addr, &addrlen) != 0) { int err = SOCKETERRNO; /* FIXME: what action should be taken?... */ Con_SafePrintf ("WIPX, getsockname: %s\n", socketerror(err)); } return 0; } //============================================================================= int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name) { Q_strcpy(name, WIPX_AddrToString(addr)); return 0; } //============================================================================= int WIPX_GetAddrFromName (const char *name, struct qsockaddr *addr) { int n; char buf[32]; n = Q_strlen(name); if (n == 12) { sprintf(buf, "00000000:%s:%u", name, net_hostport); return WIPX_StringToAddr (buf, addr); } if (n == 21) { sprintf(buf, "%s:%u", name, net_hostport); return WIPX_StringToAddr (buf, addr); } if (n > 21 && n <= 27) return WIPX_StringToAddr (name, addr); return -1; } //============================================================================= int WIPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) { if (addr1->qsa_family != addr2->qsa_family) return -1; if (*((struct sockaddr_ipx *)addr1)->sa_netnum && *((struct sockaddr_ipx *)addr2)->sa_netnum) { if (memcmp(((struct sockaddr_ipx *)addr1)->sa_netnum, ((struct sockaddr_ipx *)addr2)->sa_netnum, 4) != 0) return -1; } if (memcmp(((struct sockaddr_ipx *)addr1)->sa_nodenum, ((struct sockaddr_ipx *)addr2)->sa_nodenum, 6) != 0) return -1; if (((struct sockaddr_ipx *)addr1)->sa_socket != ((struct sockaddr_ipx *)addr2)->sa_socket) return 1; return 0; } //============================================================================= int WIPX_GetSocketPort (struct qsockaddr *addr) { return ntohs(((struct sockaddr_ipx *)addr)->sa_socket); } int WIPX_SetSocketPort (struct qsockaddr *addr, int port) { ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)port); return 0; } //============================================================================= �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/crc.c�����������������������������������������������������������������������0000644�0000000�0000000�00000007157�11336354077�014455� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* crc.c */ #include "quakedef.h" #include "crc.h" // this is a 16 bit, non-reflected CRC using the polynomial 0x1021 // and the initial and final xor values shown below... in other words, the // CCITT standard CRC used by XMODEM #define CRC_INIT_VALUE 0xffff #define CRC_XOR_VALUE 0x0000 static unsigned short crctable[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; void CRC_Init(unsigned short *crcvalue) { *crcvalue = CRC_INIT_VALUE; } void CRC_ProcessByte(unsigned short *crcvalue, byte data) { *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; } unsigned short CRC_Value(unsigned short crcvalue) { return crcvalue ^ CRC_XOR_VALUE; } //johnfitz -- texture crc unsigned short CRC_Block (byte *start, int count) { unsigned short crc; CRC_Init (&crc); while (count--) crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++]; return crc; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_sys.h�������������������������������������������������������������������0000644�0000000�0000000�00000013310�12424476246�015365� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * net_sys.h -- common network system header. * - depends on arch_def.h * - may depend on q_stdinc.h * * Copyright (C) 2007-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #ifndef __NET_SYS_H__ #define __NET_SYS_H__ #include <sys/types.h> #include <errno.h> #include <stddef.h> #include <limits.h> #if defined(PLATFORM_BSD) || defined(PLATFORM_OSX) || \ defined(PLATFORM_AMIGA) /* bsdsocket.library */ || \ defined(__GNU__) /* GNU/Hurd */ || defined(__riscos__) /* struct sockaddr has unsigned char sa_len as the first member in BSD * variants and the family member is also an unsigned char instead of an * unsigned short. This should matter only when PLATFORM_UNIX is defined, * however, checking for the offset of sa_family in every platform that * provide a struct sockaddr doesn't hurt either (see down below for the * compile time asserts.) */ /* FIXME : GET RID OF THIS ABOMINATION !!! */ #define HAVE_SA_LEN 1 #define SA_FAM_OFFSET 1 #else #undef HAVE_SA_LEN #define SA_FAM_OFFSET 0 #endif /* BSD, sockaddr */ /* unix includes and compatibility macros */ #if defined(PLATFORM_UNIX) || defined(PLATFORM_RISCOS) #include <sys/param.h> #include <sys/ioctl.h> #if defined(__sun) || defined(sun) #include <sys/filio.h> #include <sys/sockio.h> #endif /* __sunos__ */ #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> typedef int sys_socket_t; #define INVALID_SOCKET (-1) #define SOCKET_ERROR (-1) #if defined(__APPLE__) && defined(SO_NKE) && !defined(SO_NOADDRERR) /* ancient Mac OS X SDKs 10.2 and older are missing socklen_t */ typedef int socklen_t; /* defining as signed int to match the old api */ #endif /* ancient OSX SDKs */ #define SOCKETERRNO errno #define ioctlsocket ioctl #define closesocket close #define selectsocket select #define IOCTLARG_P(x) /* (char *) */ x #define NET_EWOULDBLOCK EWOULDBLOCK #define NET_ECONNREFUSED ECONNREFUSED #define socketerror(x) strerror((x)) /* Verify that we defined HAVE_SA_LEN correctly: */ COMPILE_TIME_ASSERT(sockaddr, offsetof(struct sockaddr, sa_family) == SA_FAM_OFFSET); #endif /* end of unix stuff */ /* amiga includes and compatibility macros */ #if defined(PLATFORM_AMIGA) /* Amiga bsdsocket.library */ #include <sys/param.h> #include <sys/ioctl.h> #include <unistd.h> #include <proto/exec.h> #include <proto/socket.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> typedef int sys_socket_t; #define INVALID_SOCKET (-1) #define SOCKET_ERROR (-1) #if !(defined(__AROS__) || defined(__amigaos4__)) typedef LONG socklen_t; /* int32_t */ #endif #if !defined(__amigaos4__) #if (LONG_MAX <= 2147483647L) typedef unsigned long in_addr_t; /* u_int32_t */ #else typedef unsigned int in_addr_t; /* u_int32_t */ #endif #endif #define SOCKETERRNO Errno() #define ioctlsocket IoctlSocket #define closesocket CloseSocket #define selectsocket(_N,_R,_W,_E,_T) \ WaitSelect((_N),(_R),(_W),(_E),(_T),NULL) #define IOCTLARG_P(x) (char *) x #if defined(__AMIGA__) && !defined(__MORPHOS__) #define inet_ntoa(x) Inet_NtoA((ULONG *)&x) #define h_errno Errno() #endif #define NET_EWOULDBLOCK EWOULDBLOCK #define NET_ECONNREFUSED ECONNREFUSED #define socketerror(x) strerror((x)) /* there is h_errno but no hstrerror() */ #define hstrerror(x) strerror((x)) /* Verify that we defined HAVE_SA_LEN correctly: */ COMPILE_TIME_ASSERT(sockaddr, offsetof(struct sockaddr, sa_family) == SA_FAM_OFFSET); #endif /* end of amiga bsdsocket.library stuff */ /* windows includes and compatibility macros */ #if defined(PLATFORM_WINDOWS) /* NOTE: winsock[2].h already includes windows.h */ #if !defined(_USE_WINSOCK2) #include <winsock.h> #else #include <winsock2.h> #include <ws2tcpip.h> #endif /* there is no in_addr_t on windows: define it as the type of the S_addr of in_addr structure */ typedef u_long in_addr_t; /* uint32_t */ /* on windows, socklen_t is to be a winsock2 thing */ #if !defined(IP_MSFILTER_SIZE) typedef int socklen_t; #endif /* socklen_t type */ typedef SOCKET sys_socket_t; #define selectsocket select #define IOCTLARG_P(x) /* (u_long *) */ x #define SOCKETERRNO WSAGetLastError() #define NET_EWOULDBLOCK WSAEWOULDBLOCK #define NET_ECONNREFUSED WSAECONNREFUSED /* must #include "wsaerror.h" for this : */ #define socketerror(x) __WSAE_StrError((x)) /* Verify that we defined HAVE_SA_LEN correctly: */ COMPILE_TIME_ASSERT(sockaddr, offsetof(struct sockaddr, sa_family) == SA_FAM_OFFSET); #endif /* end of windows stuff */ /* macros which may still be missing */ #if !defined(INADDR_NONE) #define INADDR_NONE ((in_addr_t) 0xffffffff) #endif /* INADDR_NONE */ #if !defined(INADDR_LOOPBACK) #define INADDR_LOOPBACK ((in_addr_t) 0x7f000001) /* 127.0.0.1 */ #endif /* INADDR_LOOPBACK */ #if !defined(MAXHOSTNAMELEN) /* SUSv2 guarantees that `Host names are limited to 255 bytes'. POSIX 1003.1-2001 guarantees that `Host names (not including the terminating NUL) are limited to HOST_NAME_MAX bytes'. */ #define MAXHOSTNAMELEN 256 #endif /* MAXHOSTNAMELEN */ #endif /* __NET_SYS_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cl_input.c������������������������������������������������������������������0000644�0000000�0000000�00000027042�12407762022�015507� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cl.input.c -- builds an intended movement command to send to the server // Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All // rights reserved. #include "quakedef.h" extern cvar_t cl_maxpitch; //johnfitz -- variable pitch clamping extern cvar_t cl_minpitch; //johnfitz -- variable pitch clamping /* =============================================================================== KEY BUTTONS Continuous button event tracking is complicated by the fact that two different input sources (say, mouse button 1 and the control key) can both press the same button, but the button should only be released when both of the pressing key have been released. When a key event issues a button command (+forward, +attack, etc), it appends its key number as a parameter to the command so it can be matched up with the release. state bit 0 is the current state of the key state bit 1 is edge triggered on the up to down transition state bit 2 is edge triggered on the down to up transition =============================================================================== */ kbutton_t in_mlook, in_klook; kbutton_t in_left, in_right, in_forward, in_back; kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack; kbutton_t in_up, in_down; int in_impulse; void KeyDown (kbutton_t *b) { int k; const char *c; c = Cmd_Argv(1); if (c[0]) k = atoi(c); else k = -1; // typed manually at the console for continuous down if (k == b->down[0] || k == b->down[1]) return; // repeating key if (!b->down[0]) b->down[0] = k; else if (!b->down[1]) b->down[1] = k; else { Con_Printf ("Three keys down for a button!\n"); return; } if (b->state & 1) return; // still down b->state |= 1 + 2; // down + impulse down } void KeyUp (kbutton_t *b) { int k; const char *c; c = Cmd_Argv(1); if (c[0]) k = atoi(c); else { // typed manually at the console, assume for unsticking, so clear all b->down[0] = b->down[1] = 0; b->state = 4; // impulse up return; } if (b->down[0] == k) b->down[0] = 0; else if (b->down[1] == k) b->down[1] = 0; else return; // key up without coresponding down (menu pass through) if (b->down[0] || b->down[1]) return; // some other key is still holding it down if (!(b->state & 1)) return; // still up (this should not happen) b->state &= ~1; // now up b->state |= 4; // impulse up } void IN_KLookDown (void) {KeyDown(&in_klook);} void IN_KLookUp (void) {KeyUp(&in_klook);} void IN_MLookDown (void) {KeyDown(&in_mlook);} void IN_MLookUp (void) { KeyUp(&in_mlook); if ( !(in_mlook.state&1) && lookspring.value) V_StartPitchDrift(); } void IN_UpDown(void) {KeyDown(&in_up);} void IN_UpUp(void) {KeyUp(&in_up);} void IN_DownDown(void) {KeyDown(&in_down);} void IN_DownUp(void) {KeyUp(&in_down);} void IN_LeftDown(void) {KeyDown(&in_left);} void IN_LeftUp(void) {KeyUp(&in_left);} void IN_RightDown(void) {KeyDown(&in_right);} void IN_RightUp(void) {KeyUp(&in_right);} void IN_ForwardDown(void) {KeyDown(&in_forward);} void IN_ForwardUp(void) {KeyUp(&in_forward);} void IN_BackDown(void) {KeyDown(&in_back);} void IN_BackUp(void) {KeyUp(&in_back);} void IN_LookupDown(void) {KeyDown(&in_lookup);} void IN_LookupUp(void) {KeyUp(&in_lookup);} void IN_LookdownDown(void) {KeyDown(&in_lookdown);} void IN_LookdownUp(void) {KeyUp(&in_lookdown);} void IN_MoveleftDown(void) {KeyDown(&in_moveleft);} void IN_MoveleftUp(void) {KeyUp(&in_moveleft);} void IN_MoverightDown(void) {KeyDown(&in_moveright);} void IN_MoverightUp(void) {KeyUp(&in_moveright);} void IN_SpeedDown(void) {KeyDown(&in_speed);} void IN_SpeedUp(void) {KeyUp(&in_speed);} void IN_StrafeDown(void) {KeyDown(&in_strafe);} void IN_StrafeUp(void) {KeyUp(&in_strafe);} void IN_AttackDown(void) {KeyDown(&in_attack);} void IN_AttackUp(void) {KeyUp(&in_attack);} void IN_UseDown (void) {KeyDown(&in_use);} void IN_UseUp (void) {KeyUp(&in_use);} void IN_JumpDown (void) {KeyDown(&in_jump);} void IN_JumpUp (void) {KeyUp(&in_jump);} void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));} /* =============== CL_KeyState Returns 0.25 if a key was pressed and released during the frame, 0.5 if it was pressed and held 0 if held then released, and 1.0 if held for the entire time =============== */ float CL_KeyState (kbutton_t *key) { float val; qboolean impulsedown, impulseup, down; impulsedown = key->state & 2; impulseup = key->state & 4; down = key->state & 1; val = 0; if (impulsedown && !impulseup) { if (down) val = 0.5; // pressed and held this frame else val = 0; // I_Error (); } if (impulseup && !impulsedown) { if (down) val = 0; // I_Error (); else val = 0; // released this frame } if (!impulsedown && !impulseup) { if (down) val = 1.0; // held the entire frame else val = 0; // up the entire frame } if (impulsedown && impulseup) { if (down) val = 0.75; // released and re-pressed this frame else val = 0.25; // pressed and released this frame } key->state &= 1; // clear impulses return val; } //========================================================================== cvar_t cl_upspeed = {"cl_upspeed","200",CVAR_NONE}; cvar_t cl_forwardspeed = {"cl_forwardspeed","200", CVAR_ARCHIVE}; cvar_t cl_backspeed = {"cl_backspeed","200", CVAR_ARCHIVE}; cvar_t cl_sidespeed = {"cl_sidespeed","350",CVAR_NONE}; cvar_t cl_movespeedkey = {"cl_movespeedkey","2.0",CVAR_NONE}; cvar_t cl_yawspeed = {"cl_yawspeed","140",CVAR_NONE}; cvar_t cl_pitchspeed = {"cl_pitchspeed","150",CVAR_NONE}; cvar_t cl_anglespeedkey = {"cl_anglespeedkey","1.5",CVAR_NONE}; /* ================ CL_AdjustAngles Moves the local angle positions ================ */ void CL_AdjustAngles (void) { float speed; float up, down; if ((cl_forwardspeed.value > 200) ^ (in_speed.state & 1)) speed = host_frametime * cl_anglespeedkey.value; else speed = host_frametime; if (!(in_strafe.state & 1)) { cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right); cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left); cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); } if (in_klook.state & 1) { V_StopPitchDrift (); cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward); cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back); } up = CL_KeyState (&in_lookup); down = CL_KeyState(&in_lookdown); cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up; cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down; if (up || down) V_StopPitchDrift (); //johnfitz -- variable pitch clamping if (cl.viewangles[PITCH] > cl_maxpitch.value) cl.viewangles[PITCH] = cl_maxpitch.value; if (cl.viewangles[PITCH] < cl_minpitch.value) cl.viewangles[PITCH] = cl_minpitch.value; //johnfitz if (cl.viewangles[ROLL] > 50) cl.viewangles[ROLL] = 50; if (cl.viewangles[ROLL] < -50) cl.viewangles[ROLL] = -50; } /* ================ CL_BaseMove Send the intended movement message to the server ================ */ void CL_BaseMove (usercmd_t *cmd) { if (cls.signon != SIGNONS) return; CL_AdjustAngles (); Q_memset (cmd, 0, sizeof(*cmd)); if (in_strafe.state & 1) { cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right); cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left); } cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright); cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft); cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up); cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down); if (! (in_klook.state & 1) ) { cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); } // // adjust for speed key // if (cl_forwardspeed.value > 200 && cl_movespeedkey.value) cmd->forwardmove /= cl_movespeedkey.value; if ((cl_forwardspeed.value > 200) ^ (in_speed.state & 1)) { cmd->forwardmove *= cl_movespeedkey.value; cmd->sidemove *= cl_movespeedkey.value; cmd->upmove *= cl_movespeedkey.value; } } /* ============== CL_SendMove ============== */ void CL_SendMove (const usercmd_t *cmd) { int i; int bits; sizebuf_t buf; byte data[128]; buf.maxsize = 128; buf.cursize = 0; buf.data = data; cl.cmd = *cmd; // // send the movement message // MSG_WriteByte (&buf, clc_move); MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times for (i=0 ; i<3 ; i++) //johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE if (cl.protocol == PROTOCOL_NETQUAKE) MSG_WriteAngle (&buf, cl.viewangles[i]); else MSG_WriteAngle16 (&buf, cl.viewangles[i]); //johnfitz MSG_WriteShort (&buf, cmd->forwardmove); MSG_WriteShort (&buf, cmd->sidemove); MSG_WriteShort (&buf, cmd->upmove); // // send button bits // bits = 0; if ( in_attack.state & 3 ) bits |= 1; in_attack.state &= ~2; if (in_jump.state & 3) bits |= 2; in_jump.state &= ~2; MSG_WriteByte (&buf, bits); MSG_WriteByte (&buf, in_impulse); in_impulse = 0; // // deliver the message // if (cls.demoplayback) return; // // allways dump the first two message, because it may contain leftover inputs // from the last level // if (++cl.movemessages <= 2) return; if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1) { Con_Printf ("CL_SendMove: lost server connection\n"); CL_Disconnect (); } } /* ============ CL_InitInput ============ */ void CL_InitInput (void) { Cmd_AddCommand ("+moveup",IN_UpDown); Cmd_AddCommand ("-moveup",IN_UpUp); Cmd_AddCommand ("+movedown",IN_DownDown); Cmd_AddCommand ("-movedown",IN_DownUp); Cmd_AddCommand ("+left",IN_LeftDown); Cmd_AddCommand ("-left",IN_LeftUp); Cmd_AddCommand ("+right",IN_RightDown); Cmd_AddCommand ("-right",IN_RightUp); Cmd_AddCommand ("+forward",IN_ForwardDown); Cmd_AddCommand ("-forward",IN_ForwardUp); Cmd_AddCommand ("+back",IN_BackDown); Cmd_AddCommand ("-back",IN_BackUp); Cmd_AddCommand ("+lookup", IN_LookupDown); Cmd_AddCommand ("-lookup", IN_LookupUp); Cmd_AddCommand ("+lookdown", IN_LookdownDown); Cmd_AddCommand ("-lookdown", IN_LookdownUp); Cmd_AddCommand ("+strafe", IN_StrafeDown); Cmd_AddCommand ("-strafe", IN_StrafeUp); Cmd_AddCommand ("+moveleft", IN_MoveleftDown); Cmd_AddCommand ("-moveleft", IN_MoveleftUp); Cmd_AddCommand ("+moveright", IN_MoverightDown); Cmd_AddCommand ("-moveright", IN_MoverightUp); Cmd_AddCommand ("+speed", IN_SpeedDown); Cmd_AddCommand ("-speed", IN_SpeedUp); Cmd_AddCommand ("+attack", IN_AttackDown); Cmd_AddCommand ("-attack", IN_AttackUp); Cmd_AddCommand ("+use", IN_UseDown); Cmd_AddCommand ("-use", IN_UseUp); Cmd_AddCommand ("+jump", IN_JumpDown); Cmd_AddCommand ("-jump", IN_JumpUp); Cmd_AddCommand ("impulse", IN_Impulse); Cmd_AddCommand ("+klook", IN_KLookDown); Cmd_AddCommand ("-klook", IN_KLookUp); Cmd_AddCommand ("+mlook", IN_MLookDown); Cmd_AddCommand ("-mlook", IN_MLookUp); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/zone.h����������������������������������������������������������������������0000644�0000000�0000000�00000006540�12407762022�014652� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __ZZONE_H #define __ZZONE_H /* memory allocation H_??? The hunk manages the entire memory block given to quake. It must be contiguous. Memory can be allocated from either the low or high end in a stack fashion. The only way memory is released is by resetting one of the pointers. Hunk allocations should be given a name, so the Hunk_Print () function can display usage. Hunk allocations are guaranteed to be 16 byte aligned. The video buffers are allocated high to avoid leaving a hole underneath server allocations when changing to a higher video mode. Z_??? Zone memory functions used for small, dynamic allocations like text strings from command input. There is only about 48K for it, allocated at the very bottom of the hunk. Cache_??? Cache memory is for objects that can be dynamically loaded and can usefully stay persistant between levels. The size of the cache fluctuates from level to level. To allocate a cachable object Temp_??? Temp memory is used for file loading and surface caching. The size of the cache memory is adjusted so that there is a minimum of 512k remaining for temp memory. ------ Top of Memory ------- high hunk allocations <--- high hunk reset point held by vid video buffer z buffer surface cache <--- high hunk used cachable memory <--- low hunk used client and server low hunk allocations <-- low hunk reset point held by host startup hunk allocations Zone block ----- Bottom of Memory ----- */ void Memory_Init (void *buf, int size); void Z_Free (void *ptr); void *Z_Malloc (int size); // returns 0 filled memory void *Z_Realloc (void *ptr, int size); char *Z_Strdup (const char *s); void *Hunk_Alloc (int size); // returns 0 filled memory void *Hunk_AllocName (int size, const char *name); void *Hunk_HighAllocName (int size, const char *name); char *Hunk_Strdup (const char *s, const char *name); int Hunk_LowMark (void); void Hunk_FreeToLowMark (int mark); int Hunk_HighMark (void); void Hunk_FreeToHighMark (int mark); void *Hunk_TempAlloc (int size); void Hunk_Check (void); typedef struct cache_user_s { void *data; } cache_user_t; void Cache_Flush (void); void *Cache_Check (cache_user_t *c); // returns the cached data, and moves to the head of the LRU list // if present, otherwise returns NULL void Cache_Free (cache_user_t *c, qboolean freetextures); //johnfitz -- added second argument void *Cache_Alloc (cache_user_t *c, int size, const char *name); // Returns NULL if all purgable data was tossed and there still // wasn't enough room. void Cache_Report (void); #endif /* __ZZONE_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_loop.c������������������������������������������������������������������0000644�0000000�0000000�00000012422�12407762022�015505� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "q_stdinc.h" #include "arch_def.h" #include "net_sys.h" #include "quakedef.h" #include "net_defs.h" #include "net_loop.h" static qboolean localconnectpending = false; static qsocket_t *loop_client = NULL; static qsocket_t *loop_server = NULL; int Loop_Init (void) { if (cls.state == ca_dedicated) return -1; return 0; } void Loop_Shutdown (void) { } void Loop_Listen (qboolean state) { } void Loop_SearchForHosts (qboolean xmit) { if (!sv.active) return; hostCacheCount = 1; if (Q_strcmp(hostname.string, "UNNAMED") == 0) Q_strcpy(hostcache[0].name, "local"); else Q_strcpy(hostcache[0].name, hostname.string); Q_strcpy(hostcache[0].map, sv.name); hostcache[0].users = net_activeconnections; hostcache[0].maxusers = svs.maxclients; hostcache[0].driver = net_driverlevel; Q_strcpy(hostcache[0].cname, "local"); } qsocket_t *Loop_Connect (const char *host) { if (Q_strcmp(host,"local") != 0) return NULL; localconnectpending = true; if (!loop_client) { if ((loop_client = NET_NewQSocket ()) == NULL) { Con_Printf("Loop_Connect: no qsocket available\n"); return NULL; } Q_strcpy (loop_client->address, "localhost"); } loop_client->receiveMessageLength = 0; loop_client->sendMessageLength = 0; loop_client->canSend = true; if (!loop_server) { if ((loop_server = NET_NewQSocket ()) == NULL) { Con_Printf("Loop_Connect: no qsocket available\n"); return NULL; } Q_strcpy (loop_server->address, "LOCAL"); } loop_server->receiveMessageLength = 0; loop_server->sendMessageLength = 0; loop_server->canSend = true; loop_client->driverdata = (void *)loop_server; loop_server->driverdata = (void *)loop_client; return loop_client; } qsocket_t *Loop_CheckNewConnections (void) { if (!localconnectpending) return NULL; localconnectpending = false; loop_server->sendMessageLength = 0; loop_server->receiveMessageLength = 0; loop_server->canSend = true; loop_client->sendMessageLength = 0; loop_client->receiveMessageLength = 0; loop_client->canSend = true; return loop_server; } static int IntAlign(int value) { return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1)); } int Loop_GetMessage (qsocket_t *sock) { int ret; int length; if (sock->receiveMessageLength == 0) return 0; ret = sock->receiveMessage[0]; length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8); // alignment byte skipped here SZ_Clear (&net_message); SZ_Write (&net_message, &sock->receiveMessage[4], length); length = IntAlign(length + 4); sock->receiveMessageLength -= length; if (sock->receiveMessageLength) memmove (sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength); if (sock->driverdata && ret == 1) ((qsocket_t *)sock->driverdata)->canSend = true; return ret; } int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data) { byte *buffer; int *bufferLength; if (!sock->driverdata) return -1; bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength; if ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE) Sys_Error("Loop_SendMessage: overflow"); buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength; // message type *buffer++ = 1; // length *buffer++ = data->cursize & 0xff; *buffer++ = data->cursize >> 8; // align buffer++; // message Q_memcpy(buffer, data->data, data->cursize); *bufferLength = IntAlign(*bufferLength + data->cursize + 4); sock->canSend = false; return 1; } int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) { byte *buffer; int *bufferLength; if (!sock->driverdata) return -1; bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength; if ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE) return 0; buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength; // message type *buffer++ = 2; // length *buffer++ = data->cursize & 0xff; *buffer++ = data->cursize >> 8; // align buffer++; // message Q_memcpy(buffer, data->data, data->cursize); *bufferLength = IntAlign(*bufferLength + data->cursize + 4); return 1; } qboolean Loop_CanSendMessage (qsocket_t *sock) { if (!sock->driverdata) return false; return sock->canSend; } qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock) { return true; } void Loop_Close (qsocket_t *sock) { if (sock->driverdata) ((qsocket_t *)sock->driverdata)->driverdata = NULL; sock->receiveMessageLength = 0; sock->sendMessageLength = 0; sock->canSend = true; if (sock == loop_client) loop_client = NULL; else loop_server = NULL; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_vidsdl.c�����������������������������������������������������������������0000644�0000000�0000000�00000152450�12642177004�015644� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // gl_vidsdl.c -- SDL GL vid component #include "quakedef.h" #include "cfgfile.h" #include "bgmusic.h" #include "resource.h" #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif //ericw -- for putting the driver into multithreaded mode #ifdef __APPLE__ #include <OpenGL/OpenGL.h> #endif #define MAX_MODE_LIST 600 //johnfitz -- was 30 #define MAX_BPPS_LIST 5 #define WARP_WIDTH 320 #define WARP_HEIGHT 200 #define MAXWIDTH 10000 #define MAXHEIGHT 10000 #define DEFAULT_SDL_FLAGS SDL_OPENGL typedef struct { int width; int height; int bpp; } vmode_t; static const char *gl_vendor; static const char *gl_renderer; static const char *gl_version; static int gl_version_major; static int gl_version_minor; static const char *gl_extensions; static char * gl_extensions_nice; static vmode_t modelist[MAX_MODE_LIST]; static int nummodes; static qboolean vid_initialized = false; #if defined(USE_SDL2) static SDL_Window *draw_context; static SDL_GLContext gl_context; #else static SDL_Surface *draw_context; #endif static qboolean vid_locked = false; //johnfitz static qboolean vid_changed = false; static void VID_Menu_Init (void); //johnfitz static void VID_Menu_f (void); //johnfitz static void VID_MenuDraw (void); static void VID_MenuKey (int key); static void ClearAllStates (void); static void GL_Init (void); static void GL_SetupState (void); //johnfitz viddef_t vid; // global video state modestate_t modestate = MS_UNINIT; qboolean scr_skipupdate; qboolean gl_mtexable = false; qboolean gl_texture_env_combine = false; //johnfitz qboolean gl_texture_env_add = false; //johnfitz qboolean gl_swap_control = false; //johnfitz qboolean gl_anisotropy_able = false; //johnfitz float gl_max_anisotropy; //johnfitz qboolean gl_texture_NPOT = false; //ericw qboolean gl_vbo_able = false; //ericw qboolean gl_glsl_able = false; //ericw GLint gl_max_texture_units = 0; //ericw qboolean gl_glsl_gamma_able = false; //ericw qboolean gl_glsl_alias_able = false; //ericw int gl_stencilbits; PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc = NULL; //johnfitz PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc = NULL; //johnfitz PFNGLCLIENTACTIVETEXTUREARBPROC GL_ClientActiveTextureFunc = NULL; //ericw PFNGLBINDBUFFERARBPROC GL_BindBufferFunc = NULL; //ericw PFNGLBUFFERDATAARBPROC GL_BufferDataFunc = NULL; //ericw PFNGLBUFFERSUBDATAARBPROC GL_BufferSubDataFunc = NULL; //ericw PFNGLDELETEBUFFERSARBPROC GL_DeleteBuffersFunc = NULL; //ericw PFNGLGENBUFFERSARBPROC GL_GenBuffersFunc = NULL; //ericw QS_PFNGLCREATESHADERPROC GL_CreateShaderFunc = NULL; //ericw QS_PFNGLDELETESHADERPROC GL_DeleteShaderFunc = NULL; //ericw QS_PFNGLDELETEPROGRAMPROC GL_DeleteProgramFunc = NULL; //ericw QS_PFNGLSHADERSOURCEPROC GL_ShaderSourceFunc = NULL; //ericw QS_PFNGLCOMPILESHADERPROC GL_CompileShaderFunc = NULL; //ericw QS_PFNGLGETSHADERIVPROC GL_GetShaderivFunc = NULL; //ericw QS_PFNGLGETSHADERINFOLOGPROC GL_GetShaderInfoLogFunc = NULL; //ericw QS_PFNGLGETPROGRAMIVPROC GL_GetProgramivFunc = NULL; //ericw QS_PFNGLGETPROGRAMINFOLOGPROC GL_GetProgramInfoLogFunc = NULL; //ericw QS_PFNGLCREATEPROGRAMPROC GL_CreateProgramFunc = NULL; //ericw QS_PFNGLATTACHSHADERPROC GL_AttachShaderFunc = NULL; //ericw QS_PFNGLLINKPROGRAMPROC GL_LinkProgramFunc = NULL; //ericw QS_PFNGLBINDATTRIBLOCATIONFUNC GL_BindAttribLocationFunc = NULL; //ericw QS_PFNGLUSEPROGRAMPROC GL_UseProgramFunc = NULL; //ericw QS_PFNGLGETATTRIBLOCATIONPROC GL_GetAttribLocationFunc = NULL; //ericw QS_PFNGLVERTEXATTRIBPOINTERPROC GL_VertexAttribPointerFunc = NULL; //ericw QS_PFNGLENABLEVERTEXATTRIBARRAYPROC GL_EnableVertexAttribArrayFunc = NULL; //ericw QS_PFNGLDISABLEVERTEXATTRIBARRAYPROC GL_DisableVertexAttribArrayFunc = NULL; //ericw QS_PFNGLGETUNIFORMLOCATIONPROC GL_GetUniformLocationFunc = NULL; //ericw QS_PFNGLUNIFORM1IPROC GL_Uniform1iFunc = NULL; //ericw QS_PFNGLUNIFORM1FPROC GL_Uniform1fFunc = NULL; //ericw QS_PFNGLUNIFORM3FPROC GL_Uniform3fFunc = NULL; //ericw QS_PFNGLUNIFORM4FPROC GL_Uniform4fFunc = NULL; //ericw //==================================== //johnfitz -- new cvars static cvar_t vid_fullscreen = {"vid_fullscreen", "0", CVAR_ARCHIVE}; // QuakeSpasm, was "1" static cvar_t vid_width = {"vid_width", "800", CVAR_ARCHIVE}; // QuakeSpasm, was 640 static cvar_t vid_height = {"vid_height", "600", CVAR_ARCHIVE}; // QuakeSpasm, was 480 static cvar_t vid_bpp = {"vid_bpp", "16", CVAR_ARCHIVE}; static cvar_t vid_vsync = {"vid_vsync", "0", CVAR_ARCHIVE}; static cvar_t vid_fsaa = {"vid_fsaa", "0", CVAR_ARCHIVE}; // QuakeSpasm static cvar_t vid_desktopfullscreen = {"vid_desktopfullscreen", "0", CVAR_ARCHIVE}; // QuakeSpasm //johnfitz cvar_t vid_gamma = {"gamma", "1", CVAR_ARCHIVE}; //johnfitz -- moved here from view.c //========================================================================== // // HARDWARE GAMMA -- johnfitz // //========================================================================== #define USE_GAMMA_RAMPS 0 #if USE_GAMMA_RAMPS static unsigned short vid_gamma_red[256]; static unsigned short vid_gamma_green[256]; static unsigned short vid_gamma_blue[256]; static unsigned short vid_sysgamma_red[256]; static unsigned short vid_sysgamma_green[256]; static unsigned short vid_sysgamma_blue[256]; #endif static qboolean gammaworks = false; // whether hw-gamma works static int fsaa; /* ================ VID_Gamma_SetGamma -- apply gamma correction ================ */ static void VID_Gamma_SetGamma (void) { if (gl_glsl_gamma_able) return; if (draw_context && gammaworks) { float value; if (vid_gamma.value > (1.0f / GAMMA_MAX)) value = 1.0f / vid_gamma.value; else value = GAMMA_MAX; #if defined(USE_SDL2) # if USE_GAMMA_RAMPS if (SDL_SetWindowGammaRamp(draw_context, vid_gamma_red, vid_gamma_green, vid_gamma_blue) != 0) Con_Printf ("VID_Gamma_SetGamma: failed on SDL_SetWindowGammaRamp\n"); # else if (SDL_SetWindowBrightness(draw_context, value) != 0) Con_Printf ("VID_Gamma_SetGamma: failed on SDL_SetWindowBrightness\n"); # endif #else /* USE_SDL2 */ # if USE_GAMMA_RAMPS if (SDL_SetGammaRamp(vid_gamma_red, vid_gamma_green, vid_gamma_blue) == -1) Con_Printf ("VID_Gamma_SetGamma: failed on SDL_SetGammaRamp\n"); # else if (SDL_SetGamma(value,value,value) == -1) Con_Printf ("VID_Gamma_SetGamma: failed on SDL_SetGamma\n"); # endif #endif /* USE_SDL2 */ } } /* ================ VID_Gamma_Restore -- restore system gamma ================ */ static void VID_Gamma_Restore (void) { if (gl_glsl_gamma_able) return; if (draw_context && gammaworks) { #if defined(USE_SDL2) # if USE_GAMMA_RAMPS if (SDL_SetWindowGammaRamp(draw_context, vid_sysgamma_red, vid_sysgamma_green, vid_sysgamma_blue) != 0) Con_Printf ("VID_Gamma_Restore: failed on SDL_SetWindowGammaRamp\n"); # else if (SDL_SetWindowBrightness(draw_context, 1) != 0) Con_Printf ("VID_Gamma_Restore: failed on SDL_SetWindowBrightness\n"); # endif #else /* USE_SDL2 */ # if USE_GAMMA_RAMPS if (SDL_SetGammaRamp(vid_sysgamma_red, vid_sysgamma_green, vid_sysgamma_blue) == -1) Con_Printf ("VID_Gamma_Restore: failed on SDL_SetGammaRamp\n"); # else if (SDL_SetGamma(1, 1, 1) == -1) Con_Printf ("VID_Gamma_Restore: failed on SDL_SetGamma\n"); # endif #endif /* USE_SDL2 */ } } /* ================ VID_Gamma_Shutdown -- called on exit ================ */ static void VID_Gamma_Shutdown (void) { VID_Gamma_Restore (); } /* ================ VID_Gamma_f -- callback when the cvar changes ================ */ static void VID_Gamma_f (cvar_t *var) { if (gl_glsl_gamma_able) return; #if USE_GAMMA_RAMPS int i; for (i = 0; i < 256; i++) { vid_gamma_red[i] = CLAMP(0, (int) (255 * pow((i + 0.5)/255.5, var->value) + 0.5), 255) << 8; vid_gamma_green[i] = vid_gamma_red[i]; vid_gamma_blue[i] = vid_gamma_red[i]; } #endif VID_Gamma_SetGamma (); } /* ================ VID_Gamma_Init -- call on init ================ */ static void VID_Gamma_Init (void) { Cvar_RegisterVariable (&vid_gamma); Cvar_SetCallback (&vid_gamma, VID_Gamma_f); if (gl_glsl_gamma_able) return; #if defined(USE_SDL2) # if USE_GAMMA_RAMPS gammaworks = (SDL_GetWindowGammaRamp(draw_context, vid_sysgamma_red, vid_sysgamma_green, vid_sysgamma_blue) == 0); if (gammaworks) gammaworks = (SDL_SetWindowGammaRamp(draw_context, vid_sysgamma_red, vid_sysgamma_green, vid_sysgamma_blue) == 0); # else gammaworks = (SDL_SetWindowBrightness(draw_context, 1) == 0); # endif #else /* USE_SDL2 */ # if USE_GAMMA_RAMPS gammaworks = (SDL_GetGammaRamp(vid_sysgamma_red, vid_sysgamma_green, vid_sysgamma_blue) == 0); if (gammaworks) gammaworks = (SDL_SetGammaRamp(vid_sysgamma_red, vid_sysgamma_green, vid_sysgamma_blue) == 0); # else gammaworks = (SDL_SetGamma(1, 1, 1) == 0); # endif #endif /* USE_SDL2 */ if (!gammaworks) Con_SafePrintf("gamma adjustment not available\n"); } /* ====================== VID_GetCurrentWidth ====================== */ static int VID_GetCurrentWidth (void) { #if defined(USE_SDL2) int w = 0, h = 0; SDL_GetWindowSize(draw_context, &w, &h); return w; #else return draw_context->w; #endif } /* ======================= VID_GetCurrentHeight ======================= */ static int VID_GetCurrentHeight (void) { #if defined(USE_SDL2) int w = 0, h = 0; SDL_GetWindowSize(draw_context, &w, &h); return h; #else return draw_context->h; #endif } /* ==================== VID_GetCurrentBPP ==================== */ static int VID_GetCurrentBPP (void) { #if defined(USE_SDL2) const Uint32 pixelFormat = SDL_GetWindowPixelFormat(draw_context); return SDL_BITSPERPIXEL(pixelFormat); #else return draw_context->format->BitsPerPixel; #endif } /* ==================== VID_GetFullscreen ==================== */ static qboolean VID_GetFullscreen (void) { #if defined(USE_SDL2) return (SDL_GetWindowFlags(draw_context) & SDL_WINDOW_FULLSCREEN) != 0; #else return (draw_context->flags & SDL_FULLSCREEN) != 0; #endif } /* ==================== VID_GetDesktopFullscreen ==================== */ static qboolean VID_GetDesktopFullscreen (void) { #if defined(USE_SDL2) return (SDL_GetWindowFlags(draw_context) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; #else return false; #endif } /* ==================== VID_GetVSync ==================== */ static qboolean VID_GetVSync (void) { #if defined(USE_SDL2) return SDL_GL_GetSwapInterval() == 1; #else int swap_control; if (SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &swap_control) == 0) return swap_control > 0; return false; #endif } /* ==================== VID_GetWindow used by pl_win.c ==================== */ void *VID_GetWindow (void) { #if defined(USE_SDL2) return draw_context; #else return NULL; #endif } /* ==================== VID_HasMouseOrInputFocus ==================== */ qboolean VID_HasMouseOrInputFocus (void) { #if defined(USE_SDL2) return (SDL_GetWindowFlags(draw_context) & (SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS)) != 0; #else return (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) != 0; #endif } /* ==================== VID_IsMinimized ==================== */ qboolean VID_IsMinimized (void) { #if defined(USE_SDL2) return !(SDL_GetWindowFlags(draw_context) & SDL_WINDOW_SHOWN); #else /* SDL_APPACTIVE in SDL 1.x means "not minimized" */ return !(SDL_GetAppState() & SDL_APPACTIVE); #endif } #if defined(USE_SDL2) /* ================ VID_SDL2_GetDisplayMode Returns a pointer to a statically allocated SDL_DisplayMode structure if there is one with the requested params on the default display. Otherwise returns NULL. This is passed to SDL_SetWindowDisplayMode to specify a pixel format with the requested bpp. If we didn't care about bpp we could just pass NULL. ================ */ static SDL_DisplayMode *VID_SDL2_GetDisplayMode(int width, int height, int bpp) { static SDL_DisplayMode mode; const int sdlmodes = SDL_GetNumDisplayModes(0); int i; for (i = 0; i < sdlmodes; i++) { if (SDL_GetDisplayMode(0, i, &mode) == 0 && mode.w == width && mode.h == height && SDL_BITSPERPIXEL(mode.format) == bpp) { return &mode; } } return NULL; } #endif /* USE_SDL2 */ /* ================ VID_ValidMode ================ */ static qboolean VID_ValidMode (int width, int height, int bpp, qboolean fullscreen) { // ignore width / height / bpp if vid_desktopfullscreen is enabled if (fullscreen && vid_desktopfullscreen.value) return true; if (width < 320) return false; if (height < 200) return false; #if defined(USE_SDL2) if (fullscreen && VID_SDL2_GetDisplayMode(width, height, bpp) == NULL) bpp = 0; #else { Uint32 flags = DEFAULT_SDL_FLAGS; if (fullscreen) flags |= SDL_FULLSCREEN; bpp = SDL_VideoModeOK(width, height, bpp, flags); } #endif switch (bpp) { case 16: case 24: case 32: break; default: return false; } return true; } /* ================ VID_SetMode ================ */ static qboolean VID_SetMode (int width, int height, int bpp, qboolean fullscreen) { int temp; Uint32 flags; char caption[50]; int depthbits, stencilbits; int fsaa_obtained; // so Con_Printfs don't mess us up by forcing vid and snd updates temp = scr_disabled_for_loading; scr_disabled_for_loading = true; CDAudio_Pause (); BGM_Pause (); /* z-buffer depth */ if (bpp == 16) { depthbits = 16; stencilbits = 0; } else { depthbits = 24; stencilbits = 8; } SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthbits); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilbits); /* fsaa */ SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, fsaa > 0 ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fsaa); q_snprintf(caption, sizeof(caption), "QuakeSpasm %1.2f.%d", (float)QUAKESPASM_VERSION, QUAKESPASM_VER_PATCH); #if defined(USE_SDL2) /* Create the window if needed, hidden */ if (!draw_context) { flags = SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN; draw_context = SDL_CreateWindow (caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); if (!draw_context) { // scale back fsaa SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); draw_context = SDL_CreateWindow (caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); } if (!draw_context) { // scale back SDL_GL_DEPTH_SIZE SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); draw_context = SDL_CreateWindow (caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); } if (!draw_context) { // scale back SDL_GL_STENCIL_SIZE SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); draw_context = SDL_CreateWindow (caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); } if (!draw_context) Sys_Error ("Couldn't create window"); } /* Ensure the window is not fullscreen */ if (VID_GetFullscreen ()) { if (SDL_SetWindowFullscreen (draw_context, 0) != 0) Sys_Error("Couldn't set fullscreen state mode"); } /* Set window size and display mode */ SDL_SetWindowSize (draw_context, width, height); SDL_SetWindowPosition (draw_context, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_SetWindowDisplayMode (draw_context, VID_SDL2_GetDisplayMode(width, height, bpp)); /* Make window fullscreen if needed, and show the window */ if (fullscreen) { Uint32 flags = vid_desktopfullscreen.value ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN; if (SDL_SetWindowFullscreen (draw_context, flags) != 0) Sys_Error ("Couldn't set fullscreen state mode"); } SDL_ShowWindow (draw_context); /* Create GL context if needed */ if (!gl_context) { gl_context = SDL_GL_CreateContext(draw_context); if (!gl_context) Sys_Error("Couldn't create GL context"); } gl_swap_control = true; if (SDL_GL_SetSwapInterval ((vid_vsync.value) ? 1 : 0) == -1) gl_swap_control = false; #else /* !defined(USE_SDL2) */ flags = DEFAULT_SDL_FLAGS; if (fullscreen) flags |= SDL_FULLSCREEN; gl_swap_control = true; if (SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, (vid_vsync.value) ? 1 : 0) == -1) gl_swap_control = false; bpp = SDL_VideoModeOK(width, height, bpp, flags); draw_context = SDL_SetVideoMode(width, height, bpp, flags); if (!draw_context) { // scale back fsaa SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); draw_context = SDL_SetVideoMode(width, height, bpp, flags); } if (!draw_context) { // scale back SDL_GL_DEPTH_SIZE SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); draw_context = SDL_SetVideoMode(width, height, bpp, flags); } if (!draw_context) { // scale back SDL_GL_STENCIL_SIZE SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); draw_context = SDL_SetVideoMode(width, height, bpp, flags); if (!draw_context) Sys_Error ("Couldn't set video mode"); } SDL_WM_SetCaption(caption, caption); #endif /* !defined(USE_SDL2) */ vid.width = VID_GetCurrentWidth(); vid.height = VID_GetCurrentHeight(); vid.conwidth = vid.width & 0xFFFFFFF8; vid.conheight = vid.conwidth * vid.height / vid.width; vid.numpages = 2; // read the obtained z-buffer depth if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depthbits) == -1) depthbits = 0; // read obtained fsaa samples if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fsaa_obtained) == -1) fsaa_obtained = 0; // read stencil bits if (SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &gl_stencilbits) == -1) gl_stencilbits = 0; modestate = VID_GetFullscreen() ? MS_FULLSCREEN : MS_WINDOWED; CDAudio_Resume (); BGM_Resume (); scr_disabled_for_loading = temp; // fix the leftover Alt from any Alt-Tab or the like that switched us away ClearAllStates (); Con_SafePrintf ("Video mode %dx%dx%d (%d-bit z-buffer, %dx FSAA) initialized\n", VID_GetCurrentWidth(), VID_GetCurrentHeight(), VID_GetCurrentBPP(), depthbits, fsaa_obtained); vid.recalc_refdef = 1; // no pending changes vid_changed = false; return true; } /* =================== VID_Changed_f -- kristian -- notify us that a value has changed that requires a vid_restart =================== */ static void VID_Changed_f (cvar_t *var) { vid_changed = true; } /* =================== VID_Restart -- johnfitz -- change video modes on the fly =================== */ static void VID_Restart (void) { int width, height, bpp; qboolean fullscreen; if (vid_locked || !vid_changed) return; width = (int)vid_width.value; height = (int)vid_height.value; bpp = (int)vid_bpp.value; fullscreen = vid_fullscreen.value ? true : false; // // validate new mode // if (!VID_ValidMode (width, height, bpp, fullscreen)) { Con_Printf ("%dx%dx%d %s is not a valid mode\n", width, height, bpp, fullscreen? "fullscreen" : "windowed"); return; } // ericw -- OS X, SDL1: textures, VBO's invalid after mode change // OS X, SDL2: still valid after mode change // To handle both cases, delete all GL objects (textures, VBO, GLSL) now. // We must not interleave deleting the old objects with creating new ones, because // one of the new objects could be given the same ID as an invalid handle // which is later deleted. TexMgr_DeleteTextureObjects (); GLSLGamma_DeleteTexture (); R_DeleteShaders (); GL_DeleteBModelVertexBuffer (); GLMesh_DeleteVertexBuffers (); // // set new mode // VID_SetMode (width, height, bpp, fullscreen); GL_Init (); TexMgr_ReloadImages (); GL_BuildBModelVertexBuffer (); GLMesh_LoadVertexBuffers (); GL_SetupState (); Fog_SetupState (); //warpimages needs to be recalculated TexMgr_RecalcWarpImageSize (); //conwidth and conheight need to be recalculated vid.conwidth = (scr_conwidth.value > 0) ? (int)scr_conwidth.value : (scr_conscale.value > 0) ? (int)(vid.width/scr_conscale.value) : vid.width; vid.conwidth = CLAMP (320, vid.conwidth, vid.width); vid.conwidth &= 0xFFFFFFF8; vid.conheight = vid.conwidth * vid.height / vid.width; // // keep cvars in line with actual mode // VID_SyncCvars(); // // update mouse grab // if (key_dest == key_console || key_dest == key_menu) { if (modestate == MS_WINDOWED) IN_Deactivate(true); else if (modestate == MS_FULLSCREEN) IN_Activate(); } } /* ================ VID_Test -- johnfitz -- like vid_restart, but asks for confirmation after switching modes ================ */ static void VID_Test (void) { int old_width, old_height, old_bpp, old_fullscreen; if (vid_locked || !vid_changed) return; // // now try the switch // old_width = VID_GetCurrentWidth(); old_height = VID_GetCurrentHeight(); old_bpp = VID_GetCurrentBPP(); old_fullscreen = VID_GetFullscreen() ? true : false; VID_Restart (); //pop up confirmation dialoge if (!SCR_ModalMessage("Would you like to keep this\nvideo mode? (y/n)\n", 5.0f)) { //revert cvars and mode Cvar_SetValueQuick (&vid_width, old_width); Cvar_SetValueQuick (&vid_height, old_height); Cvar_SetValueQuick (&vid_bpp, old_bpp); Cvar_SetQuick (&vid_fullscreen, old_fullscreen ? "1" : "0"); VID_Restart (); } } /* ================ VID_Unlock -- johnfitz ================ */ static void VID_Unlock (void) { vid_locked = false; VID_SyncCvars(); } //============================================================================== // // OPENGL STUFF // //============================================================================== /* =============== GL_MakeNiceExtensionsList -- johnfitz =============== */ static char *GL_MakeNiceExtensionsList (const char *in) { char *copy, *token, *out; int i, count; if (!in) return Z_Strdup("(none)"); //each space will be replaced by 4 chars, so count the spaces before we malloc for (i = 0, count = 1; i < (int) strlen(in); i++) { if (in[i] == ' ') count++; } out = (char *) Z_Malloc (strlen(in) + count*3 + 1); //usually about 1-2k out[0] = 0; copy = (char *) Z_Strdup(in); for (token = strtok(copy, " "); token; token = strtok(NULL, " ")) { strcat(out, "\n "); strcat(out, token); } Z_Free (copy); return out; } /* =============== GL_Info_f -- johnfitz =============== */ static void GL_Info_f (void) { Con_SafePrintf ("GL_VENDOR: %s\n", gl_vendor); Con_SafePrintf ("GL_RENDERER: %s\n", gl_renderer); Con_SafePrintf ("GL_VERSION: %s\n", gl_version); Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions_nice); } /* =============== GL_CheckExtensions =============== */ static qboolean GL_ParseExtensionList (const char *list, const char *name) { const char *start; const char *where, *terminator; if (!list || !name || !*name) return false; if (strchr(name, ' ') != NULL) return false; // extension names must not have spaces start = list; while (1) { where = strstr (start, name); if (!where) break; terminator = where + strlen (name); if (where == start || where[-1] == ' ') if (*terminator == ' ' || *terminator == '\0') return true; start = terminator; } return false; } static void GL_CheckExtensions (void) { int swap_control; // ARB_vertex_buffer_object // if (COM_CheckParm("-novbo")) Con_Warning ("Vertex buffer objects disabled at command line\n"); else if (gl_version_major < 1 || (gl_version_major == 1 && gl_version_minor < 5)) Con_Warning ("OpenGL version < 1.5, skipping ARB_vertex_buffer_object check\n"); else { GL_BindBufferFunc = (PFNGLBINDBUFFERARBPROC) SDL_GL_GetProcAddress("glBindBufferARB"); GL_BufferDataFunc = (PFNGLBUFFERDATAARBPROC) SDL_GL_GetProcAddress("glBufferDataARB"); GL_BufferSubDataFunc = (PFNGLBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glBufferSubDataARB"); GL_DeleteBuffersFunc = (PFNGLDELETEBUFFERSARBPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB"); GL_GenBuffersFunc = (PFNGLGENBUFFERSARBPROC) SDL_GL_GetProcAddress("glGenBuffersARB"); if (GL_BindBufferFunc && GL_BufferDataFunc && GL_BufferSubDataFunc && GL_DeleteBuffersFunc && GL_GenBuffersFunc) { Con_Printf("FOUND: ARB_vertex_buffer_object\n"); gl_vbo_able = true; } else { Con_Warning ("ARB_vertex_buffer_object not available\n"); } } // multitexture // if (COM_CheckParm("-nomtex")) Con_Warning ("Mutitexture disabled at command line\n"); else if (GL_ParseExtensionList(gl_extensions, "GL_ARB_multitexture")) { GL_MTexCoord2fFunc = (PFNGLMULTITEXCOORD2FARBPROC) SDL_GL_GetProcAddress("glMultiTexCoord2fARB"); GL_SelectTextureFunc = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB"); GL_ClientActiveTextureFunc = (PFNGLCLIENTACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glClientActiveTextureARB"); if (GL_MTexCoord2fFunc && GL_SelectTextureFunc && GL_ClientActiveTextureFunc) { Con_Printf("FOUND: ARB_multitexture\n"); gl_mtexable = true; glGetIntegerv(GL_MAX_TEXTURE_UNITS, &gl_max_texture_units); Con_Printf("GL_MAX_TEXTURE_UNITS: %d\n", (int)gl_max_texture_units); } else { Con_Warning ("Couldn't link to multitexture functions\n"); } } else { Con_Warning ("multitexture not supported (extension not found)\n"); } // texture_env_combine // if (COM_CheckParm("-nocombine")) Con_Warning ("texture_env_combine disabled at command line\n"); else if (GL_ParseExtensionList(gl_extensions, "GL_ARB_texture_env_combine")) { Con_Printf("FOUND: ARB_texture_env_combine\n"); gl_texture_env_combine = true; } else if (GL_ParseExtensionList(gl_extensions, "GL_EXT_texture_env_combine")) { Con_Printf("FOUND: EXT_texture_env_combine\n"); gl_texture_env_combine = true; } else { Con_Warning ("texture_env_combine not supported\n"); } // texture_env_add // if (COM_CheckParm("-noadd")) Con_Warning ("texture_env_add disabled at command line\n"); else if (GL_ParseExtensionList(gl_extensions, "GL_ARB_texture_env_add")) { Con_Printf("FOUND: ARB_texture_env_add\n"); gl_texture_env_add = true; } else if (GL_ParseExtensionList(gl_extensions, "GL_EXT_texture_env_add")) { Con_Printf("FOUND: EXT_texture_env_add\n"); gl_texture_env_add = true; } else { Con_Warning ("texture_env_add not supported\n"); } // swap control // if (!gl_swap_control) { #if defined(USE_SDL2) Con_Warning ("vertical sync not supported (SDL_GL_SetSwapInterval failed)\n"); #else Con_Warning ("vertical sync not supported (SDL_GL_SetAttribute failed)\n"); #endif } #if defined(USE_SDL2) else if ((swap_control = SDL_GL_GetSwapInterval()) == -1) #else else if (SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &swap_control) == -1) #endif { gl_swap_control = false; #if defined(USE_SDL2) Con_Warning ("vertical sync not supported (SDL_GL_GetSwapInterval failed)\n"); #else Con_Warning ("vertical sync not supported (SDL_GL_GetAttribute failed)\n"); #endif } else if ((vid_vsync.value && swap_control != 1) || (!vid_vsync.value && swap_control != 0)) { gl_swap_control = false; Con_Warning ("vertical sync not supported (swap_control doesn't match vid_vsync)\n"); } else { #if defined(USE_SDL2) Con_Printf("FOUND: SDL_GL_SetSwapInterval\n"); #else Con_Printf("FOUND: SDL_GL_SWAP_CONTROL\n"); #endif } // anisotropic filtering // if (GL_ParseExtensionList(gl_extensions, "GL_EXT_texture_filter_anisotropic")) { float test1,test2; GLuint tex; // test to make sure we really have control over it // 1.0 and 2.0 should always be legal values glGenTextures(1, &tex); glBindTexture (GL_TEXTURE_2D, tex); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); glGetTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &test1); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f); glGetTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &test2); glDeleteTextures(1, &tex); if (test1 == 1 && test2 == 2) { Con_Printf("FOUND: EXT_texture_filter_anisotropic\n"); gl_anisotropy_able = true; } else { Con_Warning ("anisotropic filtering locked by driver. Current driver setting is %f\n", test1); } //get max value either way, so the menu and stuff know it glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_anisotropy); if (gl_max_anisotropy < 2) { gl_anisotropy_able = false; gl_max_anisotropy = 1; Con_Warning ("anisotropic filtering broken: disabled\n"); } } else { gl_max_anisotropy = 1; Con_Warning ("texture_filter_anisotropic not supported\n"); } // texture_non_power_of_two // if (COM_CheckParm("-notexturenpot")) Con_Warning ("texture_non_power_of_two disabled at command line\n"); else if (GL_ParseExtensionList(gl_extensions, "GL_ARB_texture_non_power_of_two")) { Con_Printf("FOUND: ARB_texture_non_power_of_two\n"); gl_texture_NPOT = true; } else { Con_Warning ("texture_non_power_of_two not supported\n"); } // GLSL // if (COM_CheckParm("-noglsl")) Con_Warning ("GLSL disabled at command line\n"); else if (gl_version_major >= 2) { GL_CreateShaderFunc = (QS_PFNGLCREATESHADERPROC) SDL_GL_GetProcAddress("glCreateShader"); GL_DeleteShaderFunc = (QS_PFNGLDELETESHADERPROC) SDL_GL_GetProcAddress("glDeleteShader"); GL_DeleteProgramFunc = (QS_PFNGLDELETEPROGRAMPROC) SDL_GL_GetProcAddress("glDeleteProgram"); GL_ShaderSourceFunc = (QS_PFNGLSHADERSOURCEPROC) SDL_GL_GetProcAddress("glShaderSource"); GL_CompileShaderFunc = (QS_PFNGLCOMPILESHADERPROC) SDL_GL_GetProcAddress("glCompileShader"); GL_GetShaderivFunc = (QS_PFNGLGETSHADERIVPROC) SDL_GL_GetProcAddress("glGetShaderiv"); GL_GetShaderInfoLogFunc = (QS_PFNGLGETSHADERINFOLOGPROC) SDL_GL_GetProcAddress("glGetShaderInfoLog"); GL_GetProgramivFunc = (QS_PFNGLGETPROGRAMIVPROC) SDL_GL_GetProcAddress("glGetProgramiv"); GL_GetProgramInfoLogFunc = (QS_PFNGLGETPROGRAMINFOLOGPROC) SDL_GL_GetProcAddress("glGetProgramInfoLog"); GL_CreateProgramFunc = (QS_PFNGLCREATEPROGRAMPROC) SDL_GL_GetProcAddress("glCreateProgram"); GL_AttachShaderFunc = (QS_PFNGLATTACHSHADERPROC) SDL_GL_GetProcAddress("glAttachShader"); GL_LinkProgramFunc = (QS_PFNGLLINKPROGRAMPROC) SDL_GL_GetProcAddress("glLinkProgram"); GL_BindAttribLocationFunc = (QS_PFNGLBINDATTRIBLOCATIONFUNC) SDL_GL_GetProcAddress("glBindAttribLocation"); GL_UseProgramFunc = (QS_PFNGLUSEPROGRAMPROC) SDL_GL_GetProcAddress("glUseProgram"); GL_GetAttribLocationFunc = (QS_PFNGLGETATTRIBLOCATIONPROC) SDL_GL_GetProcAddress("glGetAttribLocation"); GL_VertexAttribPointerFunc = (QS_PFNGLVERTEXATTRIBPOINTERPROC) SDL_GL_GetProcAddress("glVertexAttribPointer"); GL_EnableVertexAttribArrayFunc = (QS_PFNGLENABLEVERTEXATTRIBARRAYPROC) SDL_GL_GetProcAddress("glEnableVertexAttribArray"); GL_DisableVertexAttribArrayFunc = (QS_PFNGLDISABLEVERTEXATTRIBARRAYPROC) SDL_GL_GetProcAddress("glDisableVertexAttribArray"); GL_GetUniformLocationFunc = (QS_PFNGLGETUNIFORMLOCATIONPROC) SDL_GL_GetProcAddress("glGetUniformLocation"); GL_Uniform1iFunc = (QS_PFNGLUNIFORM1IPROC) SDL_GL_GetProcAddress("glUniform1i"); GL_Uniform1fFunc = (QS_PFNGLUNIFORM1FPROC) SDL_GL_GetProcAddress("glUniform1f"); GL_Uniform3fFunc = (QS_PFNGLUNIFORM3FPROC) SDL_GL_GetProcAddress("glUniform3f"); GL_Uniform4fFunc = (QS_PFNGLUNIFORM4FPROC) SDL_GL_GetProcAddress("glUniform4f"); if (GL_CreateShaderFunc && GL_DeleteShaderFunc && GL_DeleteProgramFunc && GL_ShaderSourceFunc && GL_CompileShaderFunc && GL_GetShaderivFunc && GL_GetShaderInfoLogFunc && GL_GetProgramivFunc && GL_GetProgramInfoLogFunc && GL_CreateProgramFunc && GL_AttachShaderFunc && GL_LinkProgramFunc && GL_BindAttribLocationFunc && GL_UseProgramFunc && GL_GetAttribLocationFunc && GL_VertexAttribPointerFunc && GL_EnableVertexAttribArrayFunc && GL_DisableVertexAttribArrayFunc && GL_GetUniformLocationFunc && GL_Uniform1iFunc && GL_Uniform1fFunc && GL_Uniform3fFunc && GL_Uniform4fFunc) { Con_Printf("FOUND: GLSL\n"); gl_glsl_able = true; } else { Con_Warning ("GLSL not available\n"); } } else { Con_Warning ("OpenGL version < 2, GLSL not available\n"); } // GLSL gamma // if (COM_CheckParm("-noglslgamma")) Con_Warning ("GLSL gamma disabled at command line\n"); else if (gl_glsl_able) { gl_glsl_gamma_able = true; } else { Con_Warning ("GLSL gamma not available, using hardware gamma\n"); } // GLSL alias model rendering // if (COM_CheckParm("-noglslalias")) Con_Warning ("GLSL alias model rendering disabled at command line\n"); else if (gl_glsl_able && gl_vbo_able && gl_max_texture_units >= 3) { gl_glsl_alias_able = true; } else { Con_Warning ("GLSL alias model rendering not available, using Fitz renderer\n"); } } /* =============== GL_SetupState -- johnfitz does all the stuff from GL_Init that needs to be done every time a new GL render context is created =============== */ static void GL_SetupState (void) { glClearColor (0.15,0.15,0.15,0); //johnfitz -- originally 1,0,0,0 glCullFace(GL_BACK); //johnfitz -- glquake used CCW with backwards culling -- let's do it right glFrontFace(GL_CW); //johnfitz -- glquake used CCW with backwards culling -- let's do it right glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.666); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glShadeModel (GL_FLAT); glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //johnfitz glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glDepthRange (0, 1); //johnfitz -- moved here becuase gl_ztrick is gone. glDepthFunc (GL_LEQUAL); //johnfitz -- moved here becuase gl_ztrick is gone. } /* =============== GL_Init =============== */ static void GL_Init (void) { gl_vendor = (const char *) glGetString (GL_VENDOR); gl_renderer = (const char *) glGetString (GL_RENDERER); gl_version = (const char *) glGetString (GL_VERSION); gl_extensions = (const char *) glGetString (GL_EXTENSIONS); if (gl_version == NULL || sscanf(gl_version, "%d.%d", &gl_version_major, &gl_version_minor) < 2) { gl_version_major = 0; gl_version_minor = 0; } if (gl_extensions_nice != NULL) Z_Free (gl_extensions_nice); gl_extensions_nice = GL_MakeNiceExtensionsList (gl_extensions); GL_CheckExtensions (); //johnfitz #ifdef __APPLE__ // ericw -- enable multi-threaded OpenGL, gives a decent FPS boost. // https://developer.apple.com/library/mac/technotes/tn2085/ if (host_parms->numcpus > 1 && kCGLNoError != CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine)) { Con_Warning ("Couldn't enable multi-threaded OpenGL"); } #endif //johnfitz -- intel video workarounds from Baker if (!strcmp(gl_vendor, "Intel")) { Con_Printf ("Intel Display Adapter detected, enabling gl_clear\n"); Cbuf_AddText ("gl_clear 1"); } //johnfitz GLAlias_CreateShaders (); GL_ClearBufferBindings (); } /* ================= GL_BeginRendering -- sets values of glx, gly, glwidth, glheight ================= */ void GL_BeginRendering (int *x, int *y, int *width, int *height) { *x = *y = 0; *width = vid.width; *height = vid.height; } /* ================= GL_EndRendering ================= */ void GL_EndRendering (void) { if (!scr_skipupdate) { #if defined(USE_SDL2) SDL_GL_SwapWindow(draw_context); #else SDL_GL_SwapBuffers(); #endif } } void VID_Shutdown (void) { if (vid_initialized) { VID_Gamma_Shutdown (); //johnfitz SDL_QuitSubSystem(SDL_INIT_VIDEO); draw_context = NULL; #if defined(USE_SDL2) gl_context = NULL; #endif PL_VID_Shutdown(); } } /* =================================================================== MAIN WINDOW =================================================================== */ /* ================ ClearAllStates ================ */ static void ClearAllStates (void) { Key_ClearStates (); IN_ClearStates (); } //========================================================================== // // COMMANDS // //========================================================================== /* ================= VID_DescribeCurrentMode_f ================= */ static void VID_DescribeCurrentMode_f (void) { if (draw_context) Con_Printf("%dx%dx%d %s\n", VID_GetCurrentWidth(), VID_GetCurrentHeight(), VID_GetCurrentBPP(), VID_GetFullscreen() ? "fullscreen" : "windowed"); } /* ================= VID_DescribeModes_f -- johnfitz -- changed formatting, and added refresh rates after each mode. ================= */ static void VID_DescribeModes_f (void) { int i; int lastwidth, lastheight, lastbpp, count; lastwidth = lastheight = lastbpp = count = 0; for (i = 0; i < nummodes; i++) { if (lastwidth != modelist[i].width || lastheight != modelist[i].height || lastbpp != modelist[i].bpp) { if (count > 0) Con_SafePrintf ("\n"); Con_SafePrintf (" %4i x %4i x %i", modelist[i].width, modelist[i].height, modelist[i].bpp); lastwidth = modelist[i].width; lastheight = modelist[i].height; lastbpp = modelist[i].bpp; count++; } } Con_Printf ("\n%i modes\n", count); } /* =================== VID_FSAA_f -- ericw -- warn that vid_fsaa requires engine restart =================== */ static void VID_FSAA_f (cvar_t *var) { // don't print the warning if vid_fsaa is set during startup if (vid_initialized) Con_Printf("%s %d requires engine restart to take effect\n", var->name, (int)var->value); } //========================================================================== // // INIT // //========================================================================== /* ================= VID_InitModelist ================= */ static void VID_InitModelist (void) { #if defined(USE_SDL2) const int sdlmodes = SDL_GetNumDisplayModes(0); int i; nummodes = 0; for (i = 0; i < sdlmodes; i++) { SDL_DisplayMode mode; if (nummodes >= MAX_MODE_LIST) break; if (SDL_GetDisplayMode(0, i, &mode) == 0) { modelist[nummodes].width = mode.w; modelist[nummodes].height = mode.h; modelist[nummodes].bpp = SDL_BITSPERPIXEL(mode.format); nummodes++; } } #else /* !defined(USE_SDL2) */ SDL_PixelFormat format; SDL_Rect **modes; Uint32 flags; int i, j, k, originalnummodes, existingmode; int bpps[] = {16, 24, 32}; // enumerate >8 bpp modes originalnummodes = nummodes = 0; format.palette = NULL; // enumerate fullscreen modes flags = DEFAULT_SDL_FLAGS | SDL_FULLSCREEN; for (i = 0; i < (int)(sizeof(bpps)/sizeof(bpps[0])); i++) { if (nummodes >= MAX_MODE_LIST) break; format.BitsPerPixel = bpps[i]; modes = SDL_ListModes(&format, flags); if (modes == (SDL_Rect **)0 || modes == (SDL_Rect **)-1) continue; for (j = 0; modes[j]; j++) { if (modes[j]->w > MAXWIDTH || modes[j]->h > MAXHEIGHT || nummodes >= MAX_MODE_LIST) continue; modelist[nummodes].width = modes[j]->w; modelist[nummodes].height = modes[j]->h; modelist[nummodes].bpp = bpps[i]; for (k=originalnummodes, existingmode = 0 ; k < nummodes ; k++) { if ((modelist[nummodes].width == modelist[k].width) && (modelist[nummodes].height == modelist[k].height) && (modelist[nummodes].bpp == modelist[k].bpp)) { existingmode = 1; break; } } if (!existingmode) { nummodes++; } } } if (nummodes == originalnummodes) Con_SafePrintf ("No fullscreen DIB modes found\n"); #endif /* !defined(USE_SDL2) */ } /* =================== VID_Init =================== */ void VID_Init (void) { static char vid_center[] = "SDL_VIDEO_CENTERED=center"; int p, width, height, bpp, display_width, display_height, display_bpp; qboolean fullscreen; const char *read_vars[] = { "vid_fullscreen", "vid_width", "vid_height", "vid_bpp", "vid_vsync", "vid_fsaa", "vid_desktopfullscreen" }; #define num_readvars ( sizeof(read_vars)/sizeof(read_vars[0]) ) Cvar_RegisterVariable (&vid_fullscreen); //johnfitz Cvar_RegisterVariable (&vid_width); //johnfitz Cvar_RegisterVariable (&vid_height); //johnfitz Cvar_RegisterVariable (&vid_bpp); //johnfitz Cvar_RegisterVariable (&vid_vsync); //johnfitz Cvar_RegisterVariable (&vid_fsaa); //QuakeSpasm Cvar_RegisterVariable (&vid_desktopfullscreen); //QuakeSpasm Cvar_SetCallback (&vid_fullscreen, VID_Changed_f); Cvar_SetCallback (&vid_width, VID_Changed_f); Cvar_SetCallback (&vid_height, VID_Changed_f); Cvar_SetCallback (&vid_bpp, VID_Changed_f); Cvar_SetCallback (&vid_vsync, VID_Changed_f); Cvar_SetCallback (&vid_fsaa, VID_FSAA_f); Cvar_SetCallback (&vid_desktopfullscreen, VID_Changed_f); Cmd_AddCommand ("vid_unlock", VID_Unlock); //johnfitz Cmd_AddCommand ("vid_restart", VID_Restart); //johnfitz Cmd_AddCommand ("vid_test", VID_Test); //johnfitz Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f); Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f); putenv (vid_center); /* SDL_putenv is problematic in versions <= 1.2.9 */ if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) Sys_Error("Couldn't init SDL video: %s", SDL_GetError()); #if defined(USE_SDL2) { SDL_DisplayMode mode; if (SDL_GetDesktopDisplayMode(0, &mode) != 0) Sys_Error("Could not get desktop display mode"); display_width = mode.w; display_height = mode.h; display_bpp = SDL_BITSPERPIXEL(mode.format); } #else { const SDL_VideoInfo *info = SDL_GetVideoInfo(); display_width = info->current_w; display_height = info->current_h; display_bpp = info->vfmt->BitsPerPixel; } #endif Cvar_SetValueQuick (&vid_bpp, (float)display_bpp); if (CFG_OpenConfig("config.cfg") == 0) { CFG_ReadCvars(read_vars, num_readvars); CFG_CloseConfig(); } CFG_ReadCvarOverrides(read_vars, num_readvars); VID_InitModelist(); width = (int)vid_width.value; height = (int)vid_height.value; bpp = (int)vid_bpp.value; fullscreen = (int)vid_fullscreen.value; fsaa = (int)vid_fsaa.value; if (COM_CheckParm("-current")) { width = display_width; height = display_height; bpp = display_bpp; fullscreen = true; } else { p = COM_CheckParm("-width"); if (p && p < com_argc-1) { width = Q_atoi(com_argv[p+1]); if(!COM_CheckParm("-height")) height = width * 3 / 4; } p = COM_CheckParm("-height"); if (p && p < com_argc-1) { height = Q_atoi(com_argv[p+1]); if(!COM_CheckParm("-width")) width = height * 4 / 3; } p = COM_CheckParm("-bpp"); if (p && p < com_argc-1) bpp = Q_atoi(com_argv[p+1]); if (COM_CheckParm("-window") || COM_CheckParm("-w")) fullscreen = false; else if (COM_CheckParm("-fullscreen") || COM_CheckParm("-f")) fullscreen = true; } p = COM_CheckParm ("-fsaa"); if (p && p < com_argc-1) fsaa = atoi(com_argv[p+1]); if (!VID_ValidMode(width, height, bpp, fullscreen)) { width = (int)vid_width.value; height = (int)vid_height.value; bpp = (int)vid_bpp.value; fullscreen = (int)vid_fullscreen.value; } if (!VID_ValidMode(width, height, bpp, fullscreen)) { width = 640; height = 480; bpp = display_bpp; fullscreen = false; } vid_initialized = true; vid.maxwarpwidth = WARP_WIDTH; vid.maxwarpheight = WARP_HEIGHT; vid.colormap = host_colormap; vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); // set window icon PL_SetWindowIcon(); VID_SetMode (width, height, bpp, fullscreen); GL_Init (); GL_SetupState (); Cmd_AddCommand ("gl_info", GL_Info_f); //johnfitz //johnfitz -- removed code creating "glquake" subdirectory vid_menucmdfn = VID_Menu_f; //johnfitz vid_menudrawfn = VID_MenuDraw; vid_menukeyfn = VID_MenuKey; VID_Gamma_Init(); //johnfitz VID_Menu_Init(); //johnfitz //QuakeSpasm: current vid settings should override config file settings. //so we have to lock the vid mode from now until after all config files are read. vid_locked = true; } // new proc by S.A., called by alt-return key binding. void VID_Toggle (void) { // disabling the fast path completely because SDL_SetWindowFullscreen was changing // the window size on SDL2/WinXP and we weren't set up to handle it. --ericw // // TODO: Clear out the dead code, reinstate the fast path using SDL_SetWindowFullscreen // inside VID_SetMode, check window size to fix WinXP issue. This will // keep all the mode changing code in one place. static qboolean vid_toggle_works = false; qboolean toggleWorked; Uint32 flags = 0; S_ClearBuffer (); if (!vid_toggle_works) goto vrestart; else if (gl_vbo_able) { // disabling the fast path because with SDL 1.2 it invalidates VBOs (using them // causes a crash, sugesting that the fullscreen toggle created a new GL context, // although texture objects remain valid for some reason). // // SDL2 does promise window resizes / fullscreen changes preserve the GL context, // so we could use the fast path with SDL2. --ericw vid_toggle_works = false; goto vrestart; } #if defined(USE_SDL2) if (!VID_GetFullscreen()) { flags = vid_desktopfullscreen.value ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN; } toggleWorked = SDL_SetWindowFullscreen(draw_context, flags) == 0; #else toggleWorked = SDL_WM_ToggleFullScreen(draw_context) == 1; #endif if (toggleWorked) { Sbar_Changed (); // Sbar seems to need refreshing modestate = VID_GetFullscreen() ? MS_FULLSCREEN : MS_WINDOWED; VID_SyncCvars(); // update mouse grab if (key_dest == key_console || key_dest == key_menu) { if (modestate == MS_WINDOWED) IN_Deactivate(true); else if (modestate == MS_FULLSCREEN) IN_Activate(); } } else { vid_toggle_works = false; Con_DPrintf ("SDL_WM_ToggleFullScreen failed, attempting VID_Restart\n"); vrestart: Cvar_SetQuick (&vid_fullscreen, VID_GetFullscreen() ? "0" : "1"); Cbuf_AddText ("vid_restart\n"); } } /* ================ VID_SyncCvars -- johnfitz -- set vid cvars to match current video mode ================ */ void VID_SyncCvars (void) { if (draw_context) { if (!VID_GetDesktopFullscreen()) { Cvar_SetValueQuick (&vid_width, VID_GetCurrentWidth()); Cvar_SetValueQuick (&vid_height, VID_GetCurrentHeight()); } Cvar_SetValueQuick (&vid_bpp, VID_GetCurrentBPP()); Cvar_SetQuick (&vid_fullscreen, VID_GetFullscreen() ? "1" : "0"); Cvar_SetQuick (&vid_vsync, VID_GetVSync() ? "1" : "0"); } vid_changed = false; } //========================================================================== // // NEW VIDEO MENU -- johnfitz // //========================================================================== enum { VID_OPT_MODE, VID_OPT_BPP, VID_OPT_FULLSCREEN, VID_OPT_VSYNC, VID_OPT_TEST, VID_OPT_APPLY, VIDEO_OPTIONS_ITEMS }; static int video_options_cursor = 0; typedef struct { int width,height; } vid_menu_mode; //TODO: replace these fixed-length arrays with hunk_allocated buffers static vid_menu_mode vid_menu_modes[MAX_MODE_LIST]; static int vid_menu_nummodes = 0; static int vid_menu_bpps[MAX_BPPS_LIST]; static int vid_menu_numbpps = 0; /* ================ VID_Menu_Init ================ */ static void VID_Menu_Init (void) { int i, j, h, w; for (i = 0; i < nummodes; i++) { w = modelist[i].width; h = modelist[i].height; for (j = 0; j < vid_menu_nummodes; j++) { if (vid_menu_modes[j].width == w && vid_menu_modes[j].height == h) break; } if (j == vid_menu_nummodes) { vid_menu_modes[j].width = w; vid_menu_modes[j].height = h; vid_menu_nummodes++; } } } /* ================ VID_Menu_RebuildBppList regenerates bpp list based on current vid_width and vid_height ================ */ static void VID_Menu_RebuildBppList (void) { int i, j, b; vid_menu_numbpps = 0; for (i = 0; i < nummodes; i++) { if (vid_menu_numbpps >= MAX_BPPS_LIST) break; //bpp list is limited to bpps available with current width/height if (modelist[i].width != vid_width.value || modelist[i].height != vid_height.value) continue; b = modelist[i].bpp; for (j = 0; j < vid_menu_numbpps; j++) { if (vid_menu_bpps[j] == b) break; } if (j == vid_menu_numbpps) { vid_menu_bpps[j] = b; vid_menu_numbpps++; } } //if there are no valid fullscreen bpps for this width/height, just pick one if (vid_menu_numbpps == 0) { Cvar_SetValueQuick (&vid_bpp, (float)modelist[0].bpp); return; } //if vid_bpp is not in the new list, change vid_bpp for (i = 0; i < vid_menu_numbpps; i++) if (vid_menu_bpps[i] == (int)(vid_bpp.value)) break; if (i == vid_menu_numbpps) Cvar_SetValueQuick (&vid_bpp, (float)vid_menu_bpps[0]); } /* ================ VID_Menu_ChooseNextMode chooses next resolution in order, then updates vid_width and vid_height cvars, then updates bpp and refreshrate lists ================ */ static void VID_Menu_ChooseNextMode (int dir) { int i; if (vid_menu_nummodes) { for (i = 0; i < vid_menu_nummodes; i++) { if (vid_menu_modes[i].width == vid_width.value && vid_menu_modes[i].height == vid_height.value) break; } if (i == vid_menu_nummodes) //can't find it in list, so it must be a custom windowed res { i = 0; } else { i += dir; if (i >= vid_menu_nummodes) i = 0; else if (i < 0) i = vid_menu_nummodes-1; } Cvar_SetValueQuick (&vid_width, (float)vid_menu_modes[i].width); Cvar_SetValueQuick (&vid_height, (float)vid_menu_modes[i].height); VID_Menu_RebuildBppList (); } } /* ================ VID_Menu_ChooseNextBpp chooses next bpp in order, then updates vid_bpp cvar ================ */ static void VID_Menu_ChooseNextBpp (int dir) { int i; if (vid_menu_numbpps) { for (i = 0; i < vid_menu_numbpps; i++) { if (vid_menu_bpps[i] == vid_bpp.value) break; } if (i == vid_menu_numbpps) //can't find it in list { i = 0; } else { i += dir; if (i >= vid_menu_numbpps) i = 0; else if (i < 0) i = vid_menu_numbpps-1; } Cvar_SetValueQuick (&vid_bpp, (float)vid_menu_bpps[i]); } } /* ================ VID_MenuKey ================ */ static void VID_MenuKey (int key) { switch (key) { case K_ESCAPE: VID_SyncCvars (); //sync cvars before leaving menu. FIXME: there are other ways to leave menu S_LocalSound ("misc/menu1.wav"); M_Menu_Options_f (); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); video_options_cursor--; if (video_options_cursor < 0) video_options_cursor = VIDEO_OPTIONS_ITEMS-1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); video_options_cursor++; if (video_options_cursor >= VIDEO_OPTIONS_ITEMS) video_options_cursor = 0; break; case K_LEFTARROW: S_LocalSound ("misc/menu3.wav"); switch (video_options_cursor) { case VID_OPT_MODE: VID_Menu_ChooseNextMode (1); break; case VID_OPT_BPP: VID_Menu_ChooseNextBpp (1); break; case VID_OPT_FULLSCREEN: Cbuf_AddText ("toggle vid_fullscreen\n"); break; case VID_OPT_VSYNC: Cbuf_AddText ("toggle vid_vsync\n"); // kristian break; default: break; } break; case K_RIGHTARROW: S_LocalSound ("misc/menu3.wav"); switch (video_options_cursor) { case VID_OPT_MODE: VID_Menu_ChooseNextMode (-1); break; case VID_OPT_BPP: VID_Menu_ChooseNextBpp (-1); break; case VID_OPT_FULLSCREEN: Cbuf_AddText ("toggle vid_fullscreen\n"); break; case VID_OPT_VSYNC: Cbuf_AddText ("toggle vid_vsync\n"); break; default: break; } break; case K_ENTER: case K_KP_ENTER: m_entersound = true; switch (video_options_cursor) { case VID_OPT_MODE: VID_Menu_ChooseNextMode (1); break; case VID_OPT_BPP: VID_Menu_ChooseNextBpp (1); break; case VID_OPT_FULLSCREEN: Cbuf_AddText ("toggle vid_fullscreen\n"); break; case VID_OPT_VSYNC: Cbuf_AddText ("toggle vid_vsync\n"); break; case VID_OPT_TEST: Cbuf_AddText ("vid_test\n"); break; case VID_OPT_APPLY: Cbuf_AddText ("vid_restart\n"); key_dest = key_game; m_state = m_none; IN_Activate(); break; default: break; } break; default: break; } } /* ================ VID_MenuDraw ================ */ static void VID_MenuDraw (void) { int i, y; qpic_t *p; const char *title; y = 4; // plaque p = Draw_CachePic ("gfx/qplaque.lmp"); M_DrawTransPic (16, y, p); //p = Draw_CachePic ("gfx/vidmodes.lmp"); p = Draw_CachePic ("gfx/p_option.lmp"); M_DrawPic ( (320-p->width)/2, y, p); y += 28; // title title = "Video Options"; M_PrintWhite ((320-8*strlen(title))/2, y, title); y += 16; // options for (i = 0; i < VIDEO_OPTIONS_ITEMS; i++) { switch (i) { case VID_OPT_MODE: M_Print (16, y, " Video mode"); M_Print (184, y, va("%ix%i", (int)vid_width.value, (int)vid_height.value)); break; case VID_OPT_BPP: M_Print (16, y, " Color depth"); M_Print (184, y, va("%i", (int)vid_bpp.value)); break; case VID_OPT_FULLSCREEN: M_Print (16, y, " Fullscreen"); M_DrawCheckbox (184, y, (int)vid_fullscreen.value); break; case VID_OPT_VSYNC: M_Print (16, y, " Vertical sync"); if (gl_swap_control) M_DrawCheckbox (184, y, (int)vid_vsync.value); else M_Print (184, y, "N/A"); break; case VID_OPT_TEST: y += 8; //separate the test and apply items M_Print (16, y, " Test changes"); break; case VID_OPT_APPLY: M_Print (16, y, " Apply changes"); break; } if (video_options_cursor == i) M_DrawCharacter (168, y, 12+((int)(realtime*4)&1)); y += 8; } } /* ================ VID_Menu_f ================ */ static void VID_Menu_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_video; m_entersound = true; //set all the cvars to match the current mode when entering the menu VID_SyncCvars (); //set up bpp and rate lists based on current cvars VID_Menu_RebuildBppList (); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/keys.h����������������������������������������������������������������������0000644�0000000�0000000�00000010236�12417114344�014646� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_KEYS_H #define _QUAKE_KEYS_H // // these are the key numbers that should be passed to Key_Event // #define K_TAB 9 #define K_ENTER 13 #define K_ESCAPE 27 #define K_SPACE 32 // normal keys should be passed as lowercased ascii #define K_BACKSPACE 127 #define K_UPARROW 128 #define K_DOWNARROW 129 #define K_LEFTARROW 130 #define K_RIGHTARROW 131 #define K_ALT 132 #define K_CTRL 133 #define K_SHIFT 134 #define K_F1 135 #define K_F2 136 #define K_F3 137 #define K_F4 138 #define K_F5 139 #define K_F6 140 #define K_F7 141 #define K_F8 142 #define K_F9 143 #define K_F10 144 #define K_F11 145 #define K_F12 146 #define K_INS 147 #define K_DEL 148 #define K_PGDN 149 #define K_PGUP 150 #define K_HOME 151 #define K_END 152 #define K_KP_NUMLOCK 153 #define K_KP_SLASH 154 #define K_KP_STAR 155 #define K_KP_MINUS 156 #define K_KP_HOME 157 #define K_KP_UPARROW 158 #define K_KP_PGUP 159 #define K_KP_PLUS 160 #define K_KP_LEFTARROW 161 #define K_KP_5 162 #define K_KP_RIGHTARROW 163 #define K_KP_END 164 #define K_KP_DOWNARROW 165 #define K_KP_PGDN 166 #define K_KP_ENTER 167 #define K_KP_INS 168 #define K_KP_DEL 169 #define K_COMMAND 170 #define K_PAUSE 255 // // mouse buttons generate virtual keys // #define K_MOUSE1 200 #define K_MOUSE2 201 #define K_MOUSE3 202 // // joystick buttons // #define K_JOY1 203 #define K_JOY2 204 #define K_JOY3 205 #define K_JOY4 206 // aux keys are for multi-buttoned joysticks to generate so they can use // the normal binding process // aux29-32: reserved for the HAT (POV) switch motion #define K_AUX1 207 #define K_AUX2 208 #define K_AUX3 209 #define K_AUX4 210 #define K_AUX5 211 #define K_AUX6 212 #define K_AUX7 213 #define K_AUX8 214 #define K_AUX9 215 #define K_AUX10 216 #define K_AUX11 217 #define K_AUX12 218 #define K_AUX13 219 #define K_AUX14 220 #define K_AUX15 221 #define K_AUX16 222 #define K_AUX17 223 #define K_AUX18 224 #define K_AUX19 225 #define K_AUX20 226 #define K_AUX21 227 #define K_AUX22 228 #define K_AUX23 229 #define K_AUX24 230 #define K_AUX25 231 #define K_AUX26 232 #define K_AUX27 233 #define K_AUX28 234 #define K_AUX29 235 #define K_AUX30 236 #define K_AUX31 237 #define K_AUX32 238 // JACK: Intellimouse(c) Mouse Wheel Support #define K_MWHEELUP 239 #define K_MWHEELDOWN 240 // thumb buttons #define K_MOUSE4 241 #define K_MOUSE5 242 #define MAXCMDLINE 256 typedef enum {key_game, key_console, key_message, key_menu} keydest_t; extern keydest_t key_dest; extern char *keybindings[256]; extern char key_lines[32][MAXCMDLINE]; extern int edit_line; extern int key_linepos; extern int key_insert; extern double key_blinktime; extern qboolean chat_team; void Key_Init (void); void Key_ClearStates (void); void Key_UpdateForDest (void); void Key_BeginInputGrab (void); void Key_EndInputGrab (void); void Key_GetGrabbedInput (int *lastkey, int *lastchar); void Key_Event (int key, qboolean down); void Char_Event (int key); qboolean Key_TextEntry (void); void Key_SetBinding (int keynum, const char *binding); const char *Key_KeynumToString (int keynum); void Key_WriteBindings (FILE *f); void Key_EndChat (void); const char *Key_GetChatBuffer (void); int Key_GetChatMsgLen (void); void History_Init (void); void History_Shutdown (void); #endif /* _QUAKE_KEYS_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/modelgen.h������������������������������������������������������������������0000644�0000000�0000000�00000006072�11340073704�015466� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _MODELGEN_H #define _MODELGEN_H // // modelgen.h: header file for model generation program // // ********************************************************* // * This file must be identical in the modelgen directory * // * and in the Quake directory, because it's used to * // * pass data from one to the other via model files. * // ********************************************************* #ifdef INCLUDELIBS #include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h> #include "cmdlib.h" #include "scriplib.h" #include "trilib.h" #include "lbmlib.h" #include "mathlib.h" #endif #define ALIAS_VERSION 6 #define ALIAS_ONSEAM 0x0020 // must match definition in spritegn.h #ifndef SYNCTYPE_T #define SYNCTYPE_T typedef enum {ST_SYNC=0, ST_RAND } synctype_t; #endif typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t; typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t; typedef struct { int ident; int version; vec3_t scale; vec3_t scale_origin; float boundingradius; vec3_t eyeposition; int numskins; int skinwidth; int skinheight; int numverts; int numtris; int numframes; synctype_t synctype; int flags; float size; } mdl_t; // TODO: could be shorts typedef struct { int onseam; int s; int t; } stvert_t; typedef struct dtriangle_s { int facesfront; int vertindex[3]; } dtriangle_t; #define DT_FACES_FRONT 0x0010 // This mirrors trivert_t in trilib.h, is present so Quake knows how to // load this data typedef struct { byte v[3]; byte lightnormalindex; } trivertx_t; typedef struct { trivertx_t bboxmin; // lightnormal isn't used trivertx_t bboxmax; // lightnormal isn't used char name[16]; // frame name from grabbing } daliasframe_t; typedef struct { int numframes; trivertx_t bboxmin; // lightnormal isn't used trivertx_t bboxmax; // lightnormal isn't used } daliasgroup_t; typedef struct { int numskins; } daliasskingroup_t; typedef struct { float interval; } daliasinterval_t; typedef struct { float interval; } daliasskininterval_t; typedef struct { aliasframetype_t type; } daliasframetype_t; typedef struct { aliasskintype_t type; } daliasskintype_t; #define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I') // little-endian "IDPO" #endif /* _MODELGEN_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/build_cross_win32-sdl2.sh���������������������������������������������������0000755�0000000�0000000�00000000714�12475156650�020267� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # Change this script to meet your needs and/or environment. TARGET=i686-w64-mingw32 PREFIX=/opt/cross_win32 PATH="$PREFIX/bin:$PATH" export PATH MAKE_CMD=make CC="$TARGET-gcc" AS="$TARGET-as" RANLIB="$TARGET-ranlib" AR="$TARGET-ar" WINDRES="$TARGET-windres" STRIP="$TARGET-strip" export PATH CC AS AR RANLIB WINDRES STRIP exec $MAKE_CMD USE_SDL2=1 WINSOCK2=1 CC=$CC AS=$AS RANLIB=$RANLIB AR=$AR WINDRES=$WINDRES STRIP=$STRIP -f Makefile.w32 $* ����������������������������������������������������quakespasm-0.91.0/Quake/view.h����������������������������������������������������������������������0000644�0000000�0000000�00000002171�12407762022�014645� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_VIEW_H #define _QUAKE_VIEW_H extern cvar_t vid_gamma; extern float v_blend[4]; void V_Init (void); void V_RenderView (void); void V_CalcBlend (void); void V_UpdateBlend (void); float V_CalcRoll (vec3_t angles, vec3_t velocity); //void V_UpdatePalette (void); //johnfitz #endif /* _QUAKE_VIEW_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/spritegn.h������������������������������������������������������������������0000644�0000000�0000000�00000005564�11340073704�015534� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __SPRITEGEN_H #define __SPRITEGEN_H // // spritegn.h: header file for sprite generation program // // ********************************************************** // * This file must be identical in the spritegen directory * // * and in the Quake directory, because it's used to * // * pass data from one to the other via .spr files. * // ********************************************************** //------------------------------------------------------- // This program generates .spr sprite package files. // The format of the files is as follows: // // dsprite_t file header structure // <repeat dsprite_t.numframes times> // <if spritegroup, repeat dspritegroup_t.numframes times> // dspriteframe_t frame header structure // sprite bitmap // <else (single sprite frame)> // dspriteframe_t frame header structure // sprite bitmap // <endrepeat> //------------------------------------------------------- #ifdef INCLUDELIBS #include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h> #include "cmdlib.h" #include "scriplib.h" #include "dictlib.h" #include "trilib.h" #include "lbmlib.h" #include "mathlib.h" #endif #define SPRITE_VERSION 1 // must match definition in modelgen.h #ifndef SYNCTYPE_T #define SYNCTYPE_T typedef enum {ST_SYNC=0, ST_RAND } synctype_t; #endif // TODO: shorten these? typedef struct { int ident; int version; int type; float boundingradius; int width; int height; int numframes; float beamlength; synctype_t synctype; } dsprite_t; #define SPR_VP_PARALLEL_UPRIGHT 0 #define SPR_FACING_UPRIGHT 1 #define SPR_VP_PARALLEL 2 #define SPR_ORIENTED 3 #define SPR_VP_PARALLEL_ORIENTED 4 typedef struct { int origin[2]; int width; int height; } dspriteframe_t; typedef struct { int numframes; } dspritegroup_t; typedef struct { float interval; } dspriteinterval_t; typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t; typedef struct { spriteframetype_t type; } dspriteframetype_t; #define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSP" #endif /* __SPRITEGEN_H */ ��������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sbar.h����������������������������������������������������������������������0000644�0000000�0000000�00000002634�12407762022�014626� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_SBAR_H #define _QUAKE_SBAR_H // the status bar is only redrawn if something has changed, but if anything // does, the entire thing will be redrawn for the next vid.numpages frames. extern int sb_lines; // scan lines to draw void Sbar_Init (void); void Sbar_LoadPics (void); void Sbar_Changed (void); // call whenever any of the client stats represented on the sbar changes void Sbar_Draw (void); // called every frame by screen void Sbar_IntermissionOverlay (void); // called each frame after the level has been completed void Sbar_FinaleOverlay (void); #endif /* _QUAKE_SBAR_H */ ����������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_modplug.c���������������������������������������������������������������0000644�0000000�0000000�00000006166�12220541170�016201� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * tracker music (module file) decoding support using libmodplug * * Copyright (C) 2013 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #include "quakedef.h" #if defined(USE_CODEC_MODPLUG) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_modplug.h" #include <libmodplug/modplug.h> static void S_MODPLUG_SetSettings (snd_stream_t *stream) { ModPlug_Settings settings; ModPlug_GetSettings(&settings); settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING; settings.mChannels = shm->channels; settings.mBits = shm->samplebits; settings.mFrequency = shm->speed; settings.mResamplingMode = MODPLUG_RESAMPLE_SPLINE;/*MODPLUG_RESAMPLE_FIR*/ settings.mLoopCount = 0; ModPlug_SetSettings(&settings); if (stream) { stream->info.rate = shm->speed; stream->info.bits = shm->samplebits; stream->info.width = stream->info.bits / 8; stream->info.channels = shm->channels; } } static qboolean S_MODPLUG_CodecInitialize (void) { return true; } static void S_MODPLUG_CodecShutdown (void) { } static qboolean S_MODPLUG_CodecOpenStream (snd_stream_t *stream) { /* need to load the whole file into memory and pass it to libmodplug */ byte *moddata; long len; int mark; len = FS_filelength (&stream->fh); mark = Hunk_LowMark(); moddata = (byte *) Hunk_Alloc(len); FS_fread(moddata, 1, len, &stream->fh); S_MODPLUG_SetSettings(stream); stream->priv = ModPlug_Load(moddata, len); Hunk_FreeToLowMark(mark); /* free original file data */ if (!stream->priv) { Con_DPrintf("Could not load module %s\n", stream->name); return false; } ModPlug_Seek((ModPlugFile*)stream->priv, 0); #if 0 /* default volume (128) sounds rather low? */ ModPlug_SetMasterVolume((ModPlugFile*)stream->priv, 384); /* 0-512 */ #endif return true; } static int S_MODPLUG_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) { return ModPlug_Read((ModPlugFile*)stream->priv, buffer, bytes); } static void S_MODPLUG_CodecCloseStream (snd_stream_t *stream) { ModPlug_Unload((ModPlugFile*)stream->priv); S_CodecUtilClose(&stream); } static int S_MODPLUG_CodecRewindStream (snd_stream_t *stream) { ModPlug_Seek((ModPlugFile*)stream->priv, 0); return 0; } snd_codec_t modplug_codec = { CODECTYPE_MOD, true, /* always available. */ "s3m", S_MODPLUG_CodecInitialize, S_MODPLUG_CodecShutdown, S_MODPLUG_CodecOpenStream, S_MODPLUG_CodecReadStream, S_MODPLUG_CodecRewindStream, S_MODPLUG_CodecCloseStream, NULL }; #endif /* USE_CODEC_MODPLUG */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/pr_cmds.c�������������������������������������������������������������������0000644�0000000�0000000�00000102372�12604644475�015333� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #define STRINGTEMP_BUFFERS 16 #define STRINGTEMP_LENGTH 1024 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH]; static byte pr_string_tempindex = 0; static char *PR_GetTempString (void) { return pr_string_temp[(STRINGTEMP_BUFFERS-1) & ++pr_string_tempindex]; } #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e)) #define MSG_BROADCAST 0 // unreliable to all #define MSG_ONE 1 // reliable to one (msg_entity) #define MSG_ALL 2 // reliable to all #define MSG_INIT 3 // write to the init string /* =============================================================================== BUILT-IN FUNCTIONS =============================================================================== */ static char *PF_VarString (int first) { int i; static char out[1024]; size_t s; out[0] = 0; s = 0; for (i = first; i < pr_argc; i++) { s = q_strlcat(out, G_STRING((OFS_PARM0+i*3)), sizeof(out)); if (s >= sizeof(out)) { Con_Warning("PF_VarString: overflow (string truncated)\n"); return out; } } if (s > 255) Con_DWarning("PF_VarString: %i characters exceeds standard limit of 255.\n", (int) s); return out; } /* ================= PF_error This is a TERMINAL error, which will kill off the entire server. Dumps self. error(value) ================= */ static void PF_error (void) { char *s; edict_t *ed; s = PF_VarString(0); Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s); ed = PROG_TO_EDICT(pr_global_struct->self); ED_Print (ed); Host_Error ("Program error"); } /* ================= PF_objerror Dumps out self, then an error message. The program is aborted and self is removed, but the level can continue. objerror(value) ================= */ static void PF_objerror (void) { char *s; edict_t *ed; s = PF_VarString(0); Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s); ed = PROG_TO_EDICT(pr_global_struct->self); ED_Print (ed); ED_Free (ed); //Host_Error ("Program error"); //johnfitz -- by design, this should not be fatal } /* ============== PF_makevectors Writes new values for v_forward, v_up, and v_right based on angles makevectors(vector) ============== */ static void PF_makevectors (void) { AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up); } /* ================= PF_setorigin This is the only valid way to move an object without using the physics of the world (setting velocity and waiting). Directly changing origin will not set internal links correctly, so clipping would be messed up. This should be called when an object is spawned, and then only if it is teleported. setorigin (entity, origin) ================= */ static void PF_setorigin (void) { edict_t *e; float *org; e = G_EDICT(OFS_PARM0); org = G_VECTOR(OFS_PARM1); VectorCopy (org, e->v.origin); SV_LinkEdict (e, false); } static void SetMinMaxSize (edict_t *e, float *minvec, float *maxvec, qboolean rotate) { float *angles; vec3_t rmin, rmax; float bounds[2][3]; float xvector[2], yvector[2]; float a; vec3_t base, transformed; int i, j, k, l; for (i = 0; i < 3; i++) if (minvec[i] > maxvec[i]) PR_RunError ("backwards mins/maxs"); rotate = false; // FIXME: implement rotation properly again if (!rotate) { VectorCopy (minvec, rmin); VectorCopy (maxvec, rmax); } else { // find min / max for rotations angles = e->v.angles; a = angles[1]/180 * M_PI; xvector[0] = cos(a); xvector[1] = sin(a); yvector[0] = -sin(a); yvector[1] = cos(a); VectorCopy (minvec, bounds[0]); VectorCopy (maxvec, bounds[1]); rmin[0] = rmin[1] = rmin[2] = 9999; rmax[0] = rmax[1] = rmax[2] = -9999; for (i = 0; i <= 1; i++) { base[0] = bounds[i][0]; for (j = 0; j <= 1; j++) { base[1] = bounds[j][1]; for (k = 0; k <= 1; k++) { base[2] = bounds[k][2]; // transform the point transformed[0] = xvector[0]*base[0] + yvector[0]*base[1]; transformed[1] = xvector[1]*base[0] + yvector[1]*base[1]; transformed[2] = base[2]; for (l = 0; l < 3; l++) { if (transformed[l] < rmin[l]) rmin[l] = transformed[l]; if (transformed[l] > rmax[l]) rmax[l] = transformed[l]; } } } } } // set derived values VectorCopy (rmin, e->v.mins); VectorCopy (rmax, e->v.maxs); VectorSubtract (maxvec, minvec, e->v.size); SV_LinkEdict (e, false); } /* ================= PF_setsize the size box is rotated by the current angle setsize (entity, minvector, maxvector) ================= */ static void PF_setsize (void) { edict_t *e; float *minvec, *maxvec; e = G_EDICT(OFS_PARM0); minvec = G_VECTOR(OFS_PARM1); maxvec = G_VECTOR(OFS_PARM2); SetMinMaxSize (e, minvec, maxvec, false); } /* ================= PF_setmodel setmodel(entity, model) ================= */ static void PF_setmodel (void) { int i; const char *m, **check; qmodel_t *mod; edict_t *e; e = G_EDICT(OFS_PARM0); m = G_STRING(OFS_PARM1); // check to see if model was properly precached for (i = 0, check = sv.model_precache; *check; i++, check++) { if (!strcmp(*check, m)) break; } if (!*check) { PR_RunError ("no precache: %s", m); } e->v.model = PR_SetEngineString(*check); e->v.modelindex = i; //SV_ModelIndex (m); mod = sv.models[ (int)e->v.modelindex]; // Mod_ForName (m, true); if (mod) //johnfitz -- correct physics cullboxes for bmodels { if (mod->type == mod_brush) SetMinMaxSize (e, mod->clipmins, mod->clipmaxs, true); else SetMinMaxSize (e, mod->mins, mod->maxs, true); } //johnfitz else SetMinMaxSize (e, vec3_origin, vec3_origin, true); } /* ================= PF_bprint broadcast print to everyone on server bprint(value) ================= */ static void PF_bprint (void) { char *s; s = PF_VarString(0); SV_BroadcastPrintf ("%s", s); } /* ================= PF_sprint single print to a specific client sprint(clientent, value) ================= */ static void PF_sprint (void) { char *s; client_t *client; int entnum; entnum = G_EDICTNUM(OFS_PARM0); s = PF_VarString(1); if (entnum < 1 || entnum > svs.maxclients) { Con_Printf ("tried to sprint to a non-client\n"); return; } client = &svs.clients[entnum-1]; MSG_WriteChar (&client->message,svc_print); MSG_WriteString (&client->message, s ); } /* ================= PF_centerprint single print to a specific client centerprint(clientent, value) ================= */ static void PF_centerprint (void) { char *s; client_t *client; int entnum; entnum = G_EDICTNUM(OFS_PARM0); s = PF_VarString(1); if (entnum < 1 || entnum > svs.maxclients) { Con_Printf ("tried to sprint to a non-client\n"); return; } client = &svs.clients[entnum-1]; MSG_WriteChar (&client->message,svc_centerprint); MSG_WriteString (&client->message, s); } /* ================= PF_normalize vector normalize(vector) ================= */ static void PF_normalize (void) { float *value1; vec3_t newvalue; float new_temp; value1 = G_VECTOR(OFS_PARM0); new_temp = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2]; new_temp = sqrt (new_temp); if (new_temp == 0) newvalue[0] = newvalue[1] = newvalue[2] = 0; else { new_temp = 1 / new_temp; newvalue[0] = value1[0] * new_temp; newvalue[1] = value1[1] * new_temp; newvalue[2] = value1[2] * new_temp; } VectorCopy (newvalue, G_VECTOR(OFS_RETURN)); } /* ================= PF_vlen scalar vlen(vector) ================= */ static void PF_vlen (void) { float *value1; float new_temp; value1 = G_VECTOR(OFS_PARM0); new_temp = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2]; new_temp = sqrt(new_temp); G_FLOAT(OFS_RETURN) = new_temp; } /* ================= PF_vectoyaw float vectoyaw(vector) ================= */ static void PF_vectoyaw (void) { float *value1; float yaw; value1 = G_VECTOR(OFS_PARM0); if (value1[1] == 0 && value1[0] == 0) yaw = 0; else { yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI); if (yaw < 0) yaw += 360; } G_FLOAT(OFS_RETURN) = yaw; } /* ================= PF_vectoangles vector vectoangles(vector) ================= */ static void PF_vectoangles (void) { float *value1; float forward; float yaw, pitch; value1 = G_VECTOR(OFS_PARM0); if (value1[1] == 0 && value1[0] == 0) { yaw = 0; if (value1[2] > 0) pitch = 90; else pitch = 270; } else { yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI); if (yaw < 0) yaw += 360; forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]); pitch = (int) (atan2(value1[2], forward) * 180 / M_PI); if (pitch < 0) pitch += 360; } G_FLOAT(OFS_RETURN+0) = pitch; G_FLOAT(OFS_RETURN+1) = yaw; G_FLOAT(OFS_RETURN+2) = 0; } /* ================= PF_Random Returns a number from 0 <= num < 1 random() ================= */ static void PF_random (void) { float num; num = (rand() & 0x7fff) / ((float)0x7fff); G_FLOAT(OFS_RETURN) = num; } /* ================= PF_particle particle(origin, color, count) ================= */ static void PF_particle (void) { float *org, *dir; float color; float count; org = G_VECTOR(OFS_PARM0); dir = G_VECTOR(OFS_PARM1); color = G_FLOAT(OFS_PARM2); count = G_FLOAT(OFS_PARM3); SV_StartParticle (org, dir, color, count); } /* ================= PF_ambientsound ================= */ static void PF_ambientsound (void) { const char *samp, **check; float *pos; float vol, attenuation; int i, soundnum; int large = false; //johnfitz -- PROTOCOL_FITZQUAKE pos = G_VECTOR (OFS_PARM0); samp = G_STRING(OFS_PARM1); vol = G_FLOAT(OFS_PARM2); attenuation = G_FLOAT(OFS_PARM3); // check to see if samp was properly precached for (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++) { if (!strcmp(*check, samp)) break; } if (!*check) { Con_Printf ("no precache: %s\n", samp); return; } //johnfitz -- PROTOCOL_FITZQUAKE if (soundnum > 255) { if (sv.protocol == PROTOCOL_NETQUAKE) return; //don't send any info protocol can't support else large = true; } //johnfitz // add an svc_spawnambient command to the level signon packet //johnfitz -- PROTOCOL_FITZQUAKE if (large) MSG_WriteByte (&sv.signon,svc_spawnstaticsound2); else MSG_WriteByte (&sv.signon,svc_spawnstaticsound); //johnfitz for (i = 0; i < 3; i++) MSG_WriteCoord(&sv.signon, pos[i]); //johnfitz -- PROTOCOL_FITZQUAKE if (large) MSG_WriteShort(&sv.signon, soundnum); else MSG_WriteByte (&sv.signon, soundnum); //johnfitz MSG_WriteByte (&sv.signon, vol*255); MSG_WriteByte (&sv.signon, attenuation*64); } /* ================= PF_sound Each entity can have eight independant sound sources, like voice, weapon, feet, etc. Channel 0 is an auto-allocate channel, the others override anything already running on that entity/channel pair. An attenuation of 0 will play full volume everywhere in the level. Larger attenuations will drop off. ================= */ static void PF_sound (void) { const char *sample; int channel; edict_t *entity; int volume; float attenuation; entity = G_EDICT(OFS_PARM0); channel = G_FLOAT(OFS_PARM1); sample = G_STRING(OFS_PARM2); volume = G_FLOAT(OFS_PARM3) * 255; attenuation = G_FLOAT(OFS_PARM4); if (volume < 0 || volume > 255) Host_Error ("SV_StartSound: volume = %i", volume); if (attenuation < 0 || attenuation > 4) Host_Error ("SV_StartSound: attenuation = %f", attenuation); if (channel < 0 || channel > 7) Host_Error ("SV_StartSound: channel = %i", channel); SV_StartSound (entity, channel, sample, volume, attenuation); } /* ================= PF_break break() ================= */ static void PF_break (void) { Con_Printf ("break statement\n"); *(int *)-4 = 0; // dump to debugger // PR_RunError ("break statement"); } /* ================= PF_traceline Used for use tracing and shot targeting Traces are blocked by bbox and exact bsp entityes, and also slide box entities if the tryents flag is set. traceline (vector1, vector2, tryents) ================= */ static void PF_traceline (void) { float *v1, *v2; trace_t trace; int nomonsters; edict_t *ent; v1 = G_VECTOR(OFS_PARM0); v2 = G_VECTOR(OFS_PARM1); nomonsters = G_FLOAT(OFS_PARM2); ent = G_EDICT(OFS_PARM3); /* FIXME FIXME FIXME: Why do we hit this with certain progs.dat ?? */ if (developer.value) { if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2])) { Con_Warning ("NAN in traceline:\nv1(%f %f %f) v2(%f %f %f)\nentity %d\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], NUM_FOR_EDICT(ent)); } } if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2])) v1[0] = v1[1] = v1[2] = 0; if (IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2])) v2[0] = v2[1] = v2[2] = 0; trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent); pr_global_struct->trace_allsolid = trace.allsolid; pr_global_struct->trace_startsolid = trace.startsolid; pr_global_struct->trace_fraction = trace.fraction; pr_global_struct->trace_inwater = trace.inwater; pr_global_struct->trace_inopen = trace.inopen; VectorCopy (trace.endpos, pr_global_struct->trace_endpos); VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal); pr_global_struct->trace_plane_dist = trace.plane.dist; if (trace.ent) pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent); else pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts); } /* ================= PF_checkpos Returns true if the given entity can move to the given position from it's current position by walking or rolling. FIXME: make work... scalar checkpos (entity, vector) ================= */ #if 0 static void PF_checkpos (void) { } #endif //============================================================================ static byte checkpvs[MAX_MAP_LEAFS/8]; static int PF_newcheckclient (int check) { int i; byte *pvs; edict_t *ent; mleaf_t *leaf; vec3_t org; // cycle to the next one if (check < 1) check = 1; if (check > svs.maxclients) check = svs.maxclients; if (check == svs.maxclients) i = 1; else i = check + 1; for ( ; ; i++) { if (i == svs.maxclients+1) i = 1; ent = EDICT_NUM(i); if (i == check) break; // didn't find anything else if (ent->free) continue; if (ent->v.health <= 0) continue; if ((int)ent->v.flags & FL_NOTARGET) continue; // anything that is a client, or has a client as an enemy break; } // get the PVS for the entity VectorAdd (ent->v.origin, ent->v.view_ofs, org); leaf = Mod_PointInLeaf (org, sv.worldmodel); pvs = Mod_LeafPVS (leaf, sv.worldmodel); memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 ); return i; } /* ================= PF_checkclient Returns a client (or object that has a client enemy) that would be a valid target. If there are more than one valid options, they are cycled each frame If (self.origin + self.viewofs) is not in the PVS of the current target, it is not returned at all. name checkclient () ================= */ #define MAX_CHECK 16 static int c_invis, c_notvis; static void PF_checkclient (void) { edict_t *ent, *self; mleaf_t *leaf; int l; vec3_t view; // find a new check if on a new frame if (sv.time - sv.lastchecktime >= 0.1) { sv.lastcheck = PF_newcheckclient (sv.lastcheck); sv.lastchecktime = sv.time; } // return check if it might be visible ent = EDICT_NUM(sv.lastcheck); if (ent->free || ent->v.health <= 0) { RETURN_EDICT(sv.edicts); return; } // if current entity can't possibly see the check entity, return 0 self = PROG_TO_EDICT(pr_global_struct->self); VectorAdd (self->v.origin, self->v.view_ofs, view); leaf = Mod_PointInLeaf (view, sv.worldmodel); l = (leaf - sv.worldmodel->leafs) - 1; if ( (l < 0) || !(checkpvs[l>>3] & (1 << (l & 7))) ) { c_notvis++; RETURN_EDICT(sv.edicts); return; } // might be able to see it c_invis++; RETURN_EDICT(ent); } //============================================================================ /* ================= PF_stuffcmd Sends text over to the client's execution buffer stuffcmd (clientent, value) ================= */ static void PF_stuffcmd (void) { int entnum; const char *str; client_t *old; entnum = G_EDICTNUM(OFS_PARM0); if (entnum < 1 || entnum > svs.maxclients) PR_RunError ("Parm 0 not a client"); str = G_STRING(OFS_PARM1); old = host_client; host_client = &svs.clients[entnum-1]; Host_ClientCommands ("%s", str); host_client = old; } /* ================= PF_localcmd Sends text over to the client's execution buffer localcmd (string) ================= */ static void PF_localcmd (void) { const char *str; str = G_STRING(OFS_PARM0); Cbuf_AddText (str); } /* ================= PF_cvar float cvar (string) ================= */ static void PF_cvar (void) { const char *str; str = G_STRING(OFS_PARM0); G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str); } /* ================= PF_cvar_set float cvar (string) ================= */ static void PF_cvar_set (void) { const char *var, *val; var = G_STRING(OFS_PARM0); val = G_STRING(OFS_PARM1); Cvar_Set (var, val); } /* ================= PF_findradius Returns a chain of entities that have origins within a spherical area findradius (origin, radius) ================= */ static void PF_findradius (void) { edict_t *ent, *chain; float rad; float *org; vec3_t eorg; int i, j; chain = (edict_t *)sv.edicts; org = G_VECTOR(OFS_PARM0); rad = G_FLOAT(OFS_PARM1); ent = NEXT_EDICT(sv.edicts); for (i = 1; i < sv.num_edicts; i++, ent = NEXT_EDICT(ent)) { if (ent->free) continue; if (ent->v.solid == SOLID_NOT) continue; for (j = 0; j < 3; j++) eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j]) * 0.5); if (VectorLength(eorg) > rad) continue; ent->v.chain = EDICT_TO_PROG(chain); chain = ent; } RETURN_EDICT(chain); } /* ========= PF_dprint ========= */ static void PF_dprint (void) { Con_DPrintf ("%s",PF_VarString(0)); } static void PF_ftos (void) { float v; char *s; v = G_FLOAT(OFS_PARM0); s = PR_GetTempString(); if (v == (int)v) sprintf (s, "%d",(int)v); else sprintf (s, "%5.1f",v); G_INT(OFS_RETURN) = PR_SetEngineString(s); } static void PF_fabs (void) { float v; v = G_FLOAT(OFS_PARM0); G_FLOAT(OFS_RETURN) = fabs(v); } static void PF_vtos (void) { char *s; s = PR_GetTempString(); sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]); G_INT(OFS_RETURN) = PR_SetEngineString(s); } static void PF_Spawn (void) { edict_t *ed; ed = ED_Alloc(); RETURN_EDICT(ed); } static void PF_Remove (void) { edict_t *ed; ed = G_EDICT(OFS_PARM0); ED_Free (ed); } // entity (entity start, .string field, string match) find = #5; static void PF_Find (void) { int e; int f; const char *s, *t; edict_t *ed; e = G_EDICTNUM(OFS_PARM0); f = G_INT(OFS_PARM1); s = G_STRING(OFS_PARM2); if (!s) PR_RunError ("PF_Find: bad search string"); for (e++ ; e < sv.num_edicts ; e++) { ed = EDICT_NUM(e); if (ed->free) continue; t = E_STRING(ed,f); if (!t) continue; if (!strcmp(t,s)) { RETURN_EDICT(ed); return; } } RETURN_EDICT(sv.edicts); } static void PR_CheckEmptyString (const char *s) { if (s[0] <= ' ') PR_RunError ("Bad string"); } static void PF_precache_file (void) { // precache_file is only used to copy files with qcc, it does nothing G_INT(OFS_RETURN) = G_INT(OFS_PARM0); } static void PF_precache_sound (void) { const char *s; int i; if (sv.state != ss_loading) PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions"); s = G_STRING(OFS_PARM0); G_INT(OFS_RETURN) = G_INT(OFS_PARM0); PR_CheckEmptyString (s); for (i = 0; i < MAX_SOUNDS; i++) { if (!sv.sound_precache[i]) { sv.sound_precache[i] = s; return; } if (!strcmp(sv.sound_precache[i], s)) return; } PR_RunError ("PF_precache_sound: overflow"); } static void PF_precache_model (void) { const char *s; int i; if (sv.state != ss_loading) PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions"); s = G_STRING(OFS_PARM0); G_INT(OFS_RETURN) = G_INT(OFS_PARM0); PR_CheckEmptyString (s); for (i = 0; i < MAX_MODELS; i++) { if (!sv.model_precache[i]) { sv.model_precache[i] = s; sv.models[i] = Mod_ForName (s, true); return; } if (!strcmp(sv.model_precache[i], s)) return; } PR_RunError ("PF_precache_model: overflow"); } static void PF_coredump (void) { ED_PrintEdicts (); } static void PF_traceon (void) { pr_trace = true; } static void PF_traceoff (void) { pr_trace = false; } static void PF_eprint (void) { ED_PrintNum (G_EDICTNUM(OFS_PARM0)); } /* =============== PF_walkmove float(float yaw, float dist) walkmove =============== */ static void PF_walkmove (void) { edict_t *ent; float yaw, dist; vec3_t move; dfunction_t *oldf; int oldself; ent = PROG_TO_EDICT(pr_global_struct->self); yaw = G_FLOAT(OFS_PARM0); dist = G_FLOAT(OFS_PARM1); if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) { G_FLOAT(OFS_RETURN) = 0; return; } yaw = yaw * M_PI * 2 / 360; move[0] = cos(yaw) * dist; move[1] = sin(yaw) * dist; move[2] = 0; // save program state, because SV_movestep may call other progs oldf = pr_xfunction; oldself = pr_global_struct->self; G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true); // restore program state pr_xfunction = oldf; pr_global_struct->self = oldself; } /* =============== PF_droptofloor void() droptofloor =============== */ static void PF_droptofloor (void) { edict_t *ent; vec3_t end; trace_t trace; ent = PROG_TO_EDICT(pr_global_struct->self); VectorCopy (ent->v.origin, end); end[2] -= 256; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); if (trace.fraction == 1 || trace.allsolid) G_FLOAT(OFS_RETURN) = 0; else { VectorCopy (trace.endpos, ent->v.origin); SV_LinkEdict (ent, false); ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = EDICT_TO_PROG(trace.ent); G_FLOAT(OFS_RETURN) = 1; } } /* =============== PF_lightstyle void(float style, string value) lightstyle =============== */ static void PF_lightstyle (void) { int style; const char *val; client_t *client; int j; style = G_FLOAT(OFS_PARM0); val = G_STRING(OFS_PARM1); // change the string in sv sv.lightstyles[style] = val; // send message to all clients on this server if (sv.state != ss_active) return; for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) { if (client->active || client->spawned) { MSG_WriteChar (&client->message, svc_lightstyle); MSG_WriteChar (&client->message, style); MSG_WriteString (&client->message, val); } } } static void PF_rint (void) { float f; f = G_FLOAT(OFS_PARM0); if (f > 0) G_FLOAT(OFS_RETURN) = (int)(f + 0.5); else G_FLOAT(OFS_RETURN) = (int)(f - 0.5); } static void PF_floor (void) { G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0)); } static void PF_ceil (void) { G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0)); } /* ============= PF_checkbottom ============= */ static void PF_checkbottom (void) { edict_t *ent; ent = G_EDICT(OFS_PARM0); G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent); } /* ============= PF_pointcontents ============= */ static void PF_pointcontents (void) { float *v; v = G_VECTOR(OFS_PARM0); G_FLOAT(OFS_RETURN) = SV_PointContents (v); } /* ============= PF_nextent entity nextent(entity) ============= */ static void PF_nextent (void) { int i; edict_t *ent; i = G_EDICTNUM(OFS_PARM0); while (1) { i++; if (i == sv.num_edicts) { RETURN_EDICT(sv.edicts); return; } ent = EDICT_NUM(i); if (!ent->free) { RETURN_EDICT(ent); return; } } } /* ============= PF_aim Pick a vector for the player to shoot along vector aim(entity, missilespeed) ============= */ cvar_t sv_aim = {"sv_aim", "1", CVAR_NONE}; // ericw -- turn autoaim off by default. was 0.93 static void PF_aim (void) { edict_t *ent, *check, *bestent; vec3_t start, dir, end, bestdir; int i, j; trace_t tr; float dist, bestdist; float speed; ent = G_EDICT(OFS_PARM0); speed = G_FLOAT(OFS_PARM1); (void) speed; /* variable set but not used */ VectorCopy (ent->v.origin, start); start[2] += 20; // try sending a trace straight VectorCopy (pr_global_struct->v_forward, dir); VectorMA (start, 2048, dir, end); tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent); if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM && (!teamplay.value || ent->v.team <= 0 || ent->v.team != tr.ent->v.team) ) { VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN)); return; } // try all possible entities VectorCopy (dir, bestdir); bestdist = sv_aim.value; bestent = NULL; check = NEXT_EDICT(sv.edicts); for (i = 1; i < sv.num_edicts; i++, check = NEXT_EDICT(check) ) { if (check->v.takedamage != DAMAGE_AIM) continue; if (check == ent) continue; if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team) continue; // don't aim at teammate for (j = 0; j < 3; j++) end[j] = check->v.origin[j] + 0.5 * (check->v.mins[j] + check->v.maxs[j]); VectorSubtract (end, start, dir); VectorNormalize (dir); dist = DotProduct (dir, pr_global_struct->v_forward); if (dist < bestdist) continue; // to far to turn tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent); if (tr.ent == check) { // can shoot at this one bestdist = dist; bestent = check; } } if (bestent) { VectorSubtract (bestent->v.origin, ent->v.origin, dir); dist = DotProduct (dir, pr_global_struct->v_forward); VectorScale (pr_global_struct->v_forward, dist, end); end[2] = dir[2]; VectorNormalize (end); VectorCopy (end, G_VECTOR(OFS_RETURN)); } else { VectorCopy (bestdir, G_VECTOR(OFS_RETURN)); } } /* ============== PF_changeyaw This was a major timewaster in progs, so it was converted to C ============== */ void PF_changeyaw (void) { edict_t *ent; float ideal, current, move, speed; ent = PROG_TO_EDICT(pr_global_struct->self); current = anglemod( ent->v.angles[1] ); ideal = ent->v.ideal_yaw; speed = ent->v.yaw_speed; if (current == ideal) return; move = ideal - current; if (ideal > current) { if (move >= 180) move = move - 360; } else { if (move <= -180) move = move + 360; } if (move > 0) { if (move > speed) move = speed; } else { if (move < -speed) move = -speed; } ent->v.angles[1] = anglemod (current + move); } /* =============================================================================== MESSAGE WRITING =============================================================================== */ static sizebuf_t *WriteDest (void) { int entnum; int dest; edict_t *ent; dest = G_FLOAT(OFS_PARM0); switch (dest) { case MSG_BROADCAST: return &sv.datagram; case MSG_ONE: ent = PROG_TO_EDICT(pr_global_struct->msg_entity); entnum = NUM_FOR_EDICT(ent); if (entnum < 1 || entnum > svs.maxclients) PR_RunError ("WriteDest: not a client"); return &svs.clients[entnum-1].message; case MSG_ALL: return &sv.reliable_datagram; case MSG_INIT: return &sv.signon; default: PR_RunError ("WriteDest: bad destination"); break; } return NULL; } static void PF_WriteByte (void) { MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1)); } static void PF_WriteChar (void) { MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1)); } static void PF_WriteShort (void) { MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1)); } static void PF_WriteLong (void) { MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1)); } static void PF_WriteAngle (void) { MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1)); } static void PF_WriteCoord (void) { MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1)); } static void PF_WriteString (void) { MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1)); } static void PF_WriteEntity (void) { MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1)); } //============================================================================= static void PF_makestatic (void) { edict_t *ent; int i; int bits = 0; //johnfitz -- PROTOCOL_FITZQUAKE ent = G_EDICT(OFS_PARM0); //johnfitz -- don't send invisible static entities if (ent->alpha == ENTALPHA_ZERO) { ED_Free (ent); return; } //johnfitz //johnfitz -- PROTOCOL_FITZQUAKE if (sv.protocol == PROTOCOL_NETQUAKE) { if (SV_ModelIndex(PR_GetString(ent->v.model)) & 0xFF00 || (int)(ent->v.frame) & 0xFF00) { ED_Free (ent); return; //can't display the correct model & frame, so don't show it at all } } else { if (SV_ModelIndex(PR_GetString(ent->v.model)) & 0xFF00) bits |= B_LARGEMODEL; if ((int)(ent->v.frame) & 0xFF00) bits |= B_LARGEFRAME; if (ent->alpha != ENTALPHA_DEFAULT) bits |= B_ALPHA; } if (bits) { MSG_WriteByte (&sv.signon, svc_spawnstatic2); MSG_WriteByte (&sv.signon, bits); } else MSG_WriteByte (&sv.signon, svc_spawnstatic); if (bits & B_LARGEMODEL) MSG_WriteShort (&sv.signon, SV_ModelIndex(PR_GetString(ent->v.model))); else MSG_WriteByte (&sv.signon, SV_ModelIndex(PR_GetString(ent->v.model))); if (bits & B_LARGEFRAME) MSG_WriteShort (&sv.signon, ent->v.frame); else MSG_WriteByte (&sv.signon, ent->v.frame); //johnfitz MSG_WriteByte (&sv.signon, ent->v.colormap); MSG_WriteByte (&sv.signon, ent->v.skin); for (i = 0; i < 3; i++) { MSG_WriteCoord(&sv.signon, ent->v.origin[i]); MSG_WriteAngle(&sv.signon, ent->v.angles[i]); } //johnfitz -- PROTOCOL_FITZQUAKE if (bits & B_ALPHA) MSG_WriteByte (&sv.signon, ent->alpha); //johnfitz // throw the entity away now ED_Free (ent); } //============================================================================= /* ============== PF_setspawnparms ============== */ static void PF_setspawnparms (void) { edict_t *ent; int i; client_t *client; ent = G_EDICT(OFS_PARM0); i = NUM_FOR_EDICT(ent); if (i < 1 || i > svs.maxclients) PR_RunError ("Entity is not a client"); // copy spawn parms out of the client_t client = svs.clients + (i-1); for (i = 0; i < NUM_SPAWN_PARMS; i++) (&pr_global_struct->parm1)[i] = client->spawn_parms[i]; } /* ============== PF_changelevel ============== */ static void PF_changelevel (void) { const char *s; // make sure we don't issue two changelevels if (svs.changelevel_issued) return; svs.changelevel_issued = true; s = G_STRING(OFS_PARM0); Cbuf_AddText (va("changelevel %s\n",s)); } static void PF_Fixme (void) { PR_RunError ("unimplemented builtin"); } static builtin_t pr_builtin[] = { PF_Fixme, PF_makevectors, // void(entity e) makevectors = #1 PF_setorigin, // void(entity e, vector o) setorigin = #2 PF_setmodel, // void(entity e, string m) setmodel = #3 PF_setsize, // void(entity e, vector min, vector max) setsize = #4 PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5 PF_break, // void() break = #6 PF_random, // float() random = #7 PF_sound, // void(entity e, float chan, string samp) sound = #8 PF_normalize, // vector(vector v) normalize = #9 PF_error, // void(string e) error = #10 PF_objerror, // void(string e) objerror = #11 PF_vlen, // float(vector v) vlen = #12 PF_vectoyaw, // float(vector v) vectoyaw = #13 PF_Spawn, // entity() spawn = #14 PF_Remove, // void(entity e) remove = #15 PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16 PF_checkclient, // entity() clientlist = #17 PF_Find, // entity(entity start, .string fld, string match) find = #18 PF_precache_sound, // void(string s) precache_sound = #19 PF_precache_model, // void(string s) precache_model = #20 PF_stuffcmd, // void(entity client, string s)stuffcmd = #21 PF_findradius, // entity(vector org, float rad) findradius = #22 PF_bprint, // void(string s) bprint = #23 PF_sprint, // void(entity client, string s) sprint = #24 PF_dprint, // void(string s) dprint = #25 PF_ftos, // void(string s) ftos = #26 PF_vtos, // void(string s) vtos = #27 PF_coredump, PF_traceon, PF_traceoff, PF_eprint, // void(entity e) debug print an entire entity PF_walkmove, // float(float yaw, float dist) walkmove PF_Fixme, // float(float yaw, float dist) walkmove PF_droptofloor, PF_lightstyle, PF_rint, PF_floor, PF_ceil, PF_Fixme, PF_checkbottom, PF_pointcontents, PF_Fixme, PF_fabs, PF_aim, PF_cvar, PF_localcmd, PF_nextent, PF_particle, PF_changeyaw, PF_Fixme, PF_vectoangles, PF_WriteByte, PF_WriteChar, PF_WriteShort, PF_WriteLong, PF_WriteCoord, PF_WriteAngle, PF_WriteString, PF_WriteEntity, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, SV_MoveToGoal, PF_precache_file, PF_makestatic, PF_changelevel, PF_Fixme, PF_cvar_set, PF_centerprint, PF_ambientsound, PF_precache_model, PF_precache_sound, // precache_sound2 is different only for qcc PF_precache_file, PF_setspawnparms }; builtin_t *pr_builtins = pr_builtin; int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sv_move.c�������������������������������������������������������������������0000644�0000000�0000000�00000022242�12407762022�015345� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_move.c -- monster movement #include "quakedef.h" #define STEPSIZE 18 /* ============= SV_CheckBottom Returns false if any part of the bottom of the entity is off an edge that is not a staircase. ============= */ int c_yes, c_no; qboolean SV_CheckBottom (edict_t *ent) { vec3_t mins, maxs, start, stop; trace_t trace; int x, y; float mid, bottom; VectorAdd (ent->v.origin, ent->v.mins, mins); VectorAdd (ent->v.origin, ent->v.maxs, maxs); // if all of the points under the corners are solid world, don't bother // with the tougher checks // the corners must be within 16 of the midpoint start[2] = mins[2] - 1; for (x=0 ; x<=1 ; x++) for (y=0 ; y<=1 ; y++) { start[0] = x ? maxs[0] : mins[0]; start[1] = y ? maxs[1] : mins[1]; if (SV_PointContents (start) != CONTENTS_SOLID) goto realcheck; } c_yes++; return true; // we got out easy realcheck: c_no++; // // check it for real... // start[2] = mins[2]; // the midpoint must be within 16 of the bottom start[0] = stop[0] = (mins[0] + maxs[0])*0.5; start[1] = stop[1] = (mins[1] + maxs[1])*0.5; stop[2] = start[2] - 2*STEPSIZE; trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); if (trace.fraction == 1.0) return false; mid = bottom = trace.endpos[2]; // the corners must be within 16 of the midpoint for (x=0 ; x<=1 ; x++) for (y=0 ; y<=1 ; y++) { start[0] = stop[0] = x ? maxs[0] : mins[0]; start[1] = stop[1] = y ? maxs[1] : mins[1]; trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); if (trace.fraction != 1.0 && trace.endpos[2] > bottom) bottom = trace.endpos[2]; if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) return false; } c_yes++; return true; } /* ============= SV_movestep Called by monster program code. The move will be adjusted for slopes and stairs, but if the move isn't possible, no move is done, false is returned, and pr_global_struct->trace_normal is set to the normal of the blocking wall ============= */ qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) { float dz; vec3_t oldorg, neworg, end; trace_t trace; int i; edict_t *enemy; // try the move VectorCopy (ent->v.origin, oldorg); VectorAdd (ent->v.origin, move, neworg); // flying monsters don't step up if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) ) { // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) { VectorAdd (ent->v.origin, move, neworg); enemy = PROG_TO_EDICT(ent->v.enemy); if (i == 0 && enemy != sv.edicts) { dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2]; if (dz > 40) neworg[2] -= 8; if (dz < 30) neworg[2] += 8; } trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent); if (trace.fraction == 1) { if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY ) return false; // swim monster left water VectorCopy (trace.endpos, ent->v.origin); if (relink) SV_LinkEdict (ent, true); return true; } if (enemy == sv.edicts) break; } return false; } // push down from a step height above the wished position neworg[2] += STEPSIZE; VectorCopy (neworg, end); end[2] -= STEPSIZE*2; trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); if (trace.allsolid) return false; if (trace.startsolid) { neworg[2] -= STEPSIZE; trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); if (trace.allsolid || trace.startsolid) return false; } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ( (int)ent->v.flags & FL_PARTIALGROUND ) { VectorAdd (ent->v.origin, move, ent->v.origin); if (relink) SV_LinkEdict (ent, true); ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; // Con_Printf ("fall down\n"); return true; } return false; // walked off an edge } // check point traces down for dangling corners VectorCopy (trace.endpos, ent->v.origin); if (!SV_CheckBottom (ent)) { if ( (int)ent->v.flags & FL_PARTIALGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) SV_LinkEdict (ent, true); return true; } VectorCopy (oldorg, ent->v.origin); return false; } if ( (int)ent->v.flags & FL_PARTIALGROUND ) { // Con_Printf ("back on ground\n"); ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND; } ent->v.groundentity = EDICT_TO_PROG(trace.ent); // the move is ok if (relink) SV_LinkEdict (ent, true); return true; } //============================================================================ /* ====================== SV_StepDirection Turns to the movement direction, and walks the current distance if facing it. ====================== */ void PF_changeyaw (void); qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) { vec3_t move, oldorigin; float delta; ent->v.ideal_yaw = yaw; PF_changeyaw(); yaw = yaw*M_PI*2 / 360; move[0] = cos(yaw)*dist; move[1] = sin(yaw)*dist; move[2] = 0; VectorCopy (ent->v.origin, oldorigin); if (SV_movestep (ent, move, false)) { delta = ent->v.angles[YAW] - ent->v.ideal_yaw; if (delta > 45 && delta < 315) { // not turned far enough, so don't take the step VectorCopy (oldorigin, ent->v.origin); } SV_LinkEdict (ent, true); return true; } SV_LinkEdict (ent, true); return false; } /* ====================== SV_FixCheckBottom ====================== */ void SV_FixCheckBottom (edict_t *ent) { // Con_Printf ("SV_FixCheckBottom\n"); ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND; } /* ================ SV_NewChaseDir ================ */ #define DI_NODIR -1 void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) { float deltax,deltay; float d[3]; float tdir, olddir, turnaround; olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 ); turnaround = anglemod(olddir - 180); deltax = enemy->v.origin[0] - actor->v.origin[0]; deltay = enemy->v.origin[1] - actor->v.origin[1]; if (deltax>10) d[1]= 0; else if (deltax<-10) d[1]= 180; else d[1]= DI_NODIR; if (deltay<-10) d[2]= 270; else if (deltay>10) d[2]= 90; else d[2]= DI_NODIR; // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { if (d[1] == 0) tdir = d[2] == 90 ? 45 : 315; else tdir = d[2] == 90 ? 135 : 215; if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; } // try other directions if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax)) { tdir=d[1]; d[1]=d[2]; d[2]=tdir; } if (d[1]!=DI_NODIR && d[1]!=turnaround && SV_StepDirection(actor, d[1], dist)) return; if (d[2]!=DI_NODIR && d[2]!=turnaround && SV_StepDirection(actor, d[2], dist)) return; /* there is no direct path to the player, so pick another direction */ if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) return; if (rand()&1) /*randomly determine direction of search*/ { for (tdir=0 ; tdir<=315 ; tdir += 45) if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) return; } else { for (tdir=315 ; tdir >=0 ; tdir -= 45) if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) return; } if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) return; actor->v.ideal_yaw = olddir; // can't move // if a bridge was pulled out from underneath a monster, it may not have // a valid standing position at all if (!SV_CheckBottom (actor)) SV_FixCheckBottom (actor); } /* ====================== SV_CloseEnough ====================== */ qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) { int i; for (i=0 ; i<3 ; i++) { if (goal->v.absmin[i] > ent->v.absmax[i] + dist) return false; if (goal->v.absmax[i] < ent->v.absmin[i] - dist) return false; } return true; } /* ====================== SV_MoveToGoal ====================== */ void SV_MoveToGoal (void) { edict_t *ent, *goal; float dist; ent = PROG_TO_EDICT(pr_global_struct->self); goal = PROG_TO_EDICT(ent->v.goalentity); dist = G_FLOAT(OFS_PARM0); if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) { G_FLOAT(OFS_RETURN) = 0; return; } // if the next step hits the enemy, return immediately if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) ) return; // bump around... if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->v.ideal_yaw, dist)) { SV_NewChaseDir (ent, goal, dist); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/world.c���������������������������������������������������������������������0000644�0000000�0000000�00000047123�12407762022�015023� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // world.c -- world query functions #include "quakedef.h" /* entities never clip against themselves, or their owner line of sight checks trace->crosscontent, but bullets don't */ typedef struct { vec3_t boxmins, boxmaxs;// enclose the test object along entire move float *mins, *maxs; // size of the moving object vec3_t mins2, maxs2; // size when clipping against mosnters float *start, *end; trace_t trace; int type; edict_t *passedict; } moveclip_t; int SV_HullPointContents (hull_t *hull, int num, vec3_t p); /* =============================================================================== HULL BOXES =============================================================================== */ static hull_t box_hull; static mclipnode_t box_clipnodes[6]; //johnfitz -- was dclipnode_t static mplane_t box_planes[6]; /* =================== SV_InitBoxHull Set up the planes and clipnodes so that the six floats of a bounding box can just be stored out and get a proper hull_t structure. =================== */ void SV_InitBoxHull (void) { int i; int side; box_hull.clipnodes = box_clipnodes; box_hull.planes = box_planes; box_hull.firstclipnode = 0; box_hull.lastclipnode = 5; for (i=0 ; i<6 ; i++) { box_clipnodes[i].planenum = i; side = i&1; box_clipnodes[i].children[side] = CONTENTS_EMPTY; if (i != 5) box_clipnodes[i].children[side^1] = i + 1; else box_clipnodes[i].children[side^1] = CONTENTS_SOLID; box_planes[i].type = i>>1; box_planes[i].normal[i>>1] = 1; } } /* =================== SV_HullForBox To keep everything totally uniform, bounding boxes are turned into small BSP trees instead of being compared directly. =================== */ hull_t *SV_HullForBox (vec3_t mins, vec3_t maxs) { box_planes[0].dist = maxs[0]; box_planes[1].dist = mins[0]; box_planes[2].dist = maxs[1]; box_planes[3].dist = mins[1]; box_planes[4].dist = maxs[2]; box_planes[5].dist = mins[2]; return &box_hull; } /* ================ SV_HullForEntity Returns a hull that can be used for testing or clipping an object of mins/maxs size. Offset is filled in to contain the adjustment that must be added to the testing object's origin to get a point to use with the returned hull. ================ */ hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset) { qmodel_t *model; vec3_t size; vec3_t hullmins, hullmaxs; hull_t *hull; // decide which clipping hull to use, based on the size if (ent->v.solid == SOLID_BSP) { // explicit hulls in the BSP model if (ent->v.movetype != MOVETYPE_PUSH) Sys_Error ("SOLID_BSP without MOVETYPE_PUSH"); model = sv.models[ (int)ent->v.modelindex ]; if (!model || model->type != mod_brush) Sys_Error ("MOVETYPE_PUSH with a non bsp model"); VectorSubtract (maxs, mins, size); if (size[0] < 3) hull = &model->hulls[0]; else if (size[0] <= 32) hull = &model->hulls[1]; else hull = &model->hulls[2]; // calculate an offset value to center the origin VectorSubtract (hull->clip_mins, mins, offset); VectorAdd (offset, ent->v.origin, offset); } else { // create a temp hull from bounding box sizes VectorSubtract (ent->v.mins, maxs, hullmins); VectorSubtract (ent->v.maxs, mins, hullmaxs); hull = SV_HullForBox (hullmins, hullmaxs); VectorCopy (ent->v.origin, offset); } return hull; } /* =============================================================================== ENTITY AREA CHECKING =============================================================================== */ typedef struct areanode_s { int axis; // -1 = leaf node float dist; struct areanode_s *children[2]; link_t trigger_edicts; link_t solid_edicts; } areanode_t; #define AREA_DEPTH 4 #define AREA_NODES 32 static areanode_t sv_areanodes[AREA_NODES]; static int sv_numareanodes; /* =============== SV_CreateAreaNode =============== */ areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs) { areanode_t *anode; vec3_t size; vec3_t mins1, maxs1, mins2, maxs2; anode = &sv_areanodes[sv_numareanodes]; sv_numareanodes++; ClearLink (&anode->trigger_edicts); ClearLink (&anode->solid_edicts); if (depth == AREA_DEPTH) { anode->axis = -1; anode->children[0] = anode->children[1] = NULL; return anode; } VectorSubtract (maxs, mins, size); if (size[0] > size[1]) anode->axis = 0; else anode->axis = 1; anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]); VectorCopy (mins, mins1); VectorCopy (mins, mins2); VectorCopy (maxs, maxs1); VectorCopy (maxs, maxs2); maxs1[anode->axis] = mins2[anode->axis] = anode->dist; anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2); anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1); return anode; } /* =============== SV_ClearWorld =============== */ void SV_ClearWorld (void) { SV_InitBoxHull (); memset (sv_areanodes, 0, sizeof(sv_areanodes)); sv_numareanodes = 0; SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs); } /* =============== SV_UnlinkEdict =============== */ static link_t **sv_link_next; static link_t **sv_link_prev; void SV_UnlinkEdict (edict_t *ent) { if (!ent->area.prev) return; // not linked in anywhere RemoveLink (&ent->area); if (sv_link_next && *sv_link_next == &ent->area) *sv_link_next = ent->area.next; if (sv_link_prev && *sv_link_prev == &ent->area) *sv_link_prev = ent->area.prev; ent->area.prev = ent->area.next = NULL; } /* ==================== SV_TouchLinks ==================== */ void SV_TouchLinks ( edict_t *ent, areanode_t *node ) { link_t *l, *next; edict_t *touch; int old_self, old_other; // touch linked edicts sv_link_next = &next; for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next) { if (!l) { // my area got removed out from under me! Con_Printf ("SV_TouchLinks: encountered NULL link!\n"); break; } next = l->next; touch = EDICT_FROM_AREA(l); if (touch == ent) continue; if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER) continue; if (ent->v.absmin[0] > touch->v.absmax[0] || ent->v.absmin[1] > touch->v.absmax[1] || ent->v.absmin[2] > touch->v.absmax[2] || ent->v.absmax[0] < touch->v.absmin[0] || ent->v.absmax[1] < touch->v.absmin[1] || ent->v.absmax[2] < touch->v.absmin[2] ) continue; old_self = pr_global_struct->self; old_other = pr_global_struct->other; pr_global_struct->self = EDICT_TO_PROG(touch); pr_global_struct->other = EDICT_TO_PROG(ent); pr_global_struct->time = sv.time; PR_ExecuteProgram (touch->v.touch); pr_global_struct->self = old_self; pr_global_struct->other = old_other; } sv_link_next = NULL; // recurse down both sides if (node->axis == -1) return; if ( ent->v.absmax[node->axis] > node->dist ) SV_TouchLinks ( ent, node->children[0] ); if ( ent->v.absmin[node->axis] < node->dist ) SV_TouchLinks ( ent, node->children[1] ); } /* =============== SV_FindTouchedLeafs =============== */ void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) { mplane_t *splitplane; mleaf_t *leaf; int sides; int leafnum; if (node->contents == CONTENTS_SOLID) return; // add an efrag if the node is a leaf if ( node->contents < 0) { if (ent->num_leafs == MAX_ENT_LEAFS) return; leaf = (mleaf_t *)node; leafnum = leaf - sv.worldmodel->leafs - 1; ent->leafnums[ent->num_leafs] = leafnum; ent->num_leafs++; return; } // NODE_MIXED splitplane = node->plane; sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane); // recurse down the contacted sides if (sides & 1) SV_FindTouchedLeafs (ent, node->children[0]); if (sides & 2) SV_FindTouchedLeafs (ent, node->children[1]); } /* =============== SV_LinkEdict =============== */ void SV_LinkEdict (edict_t *ent, qboolean touch_triggers) { areanode_t *node; if (ent->area.prev) SV_UnlinkEdict (ent); // unlink from old position if (ent == sv.edicts) return; // don't add the world if (ent->free) return; // set the abs box VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin); VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax); // // to make items easier to pick up and allow them to be grabbed off // of shelves, the abs sizes are expanded // if ((int)ent->v.flags & FL_ITEM) { ent->v.absmin[0] -= 15; ent->v.absmin[1] -= 15; ent->v.absmax[0] += 15; ent->v.absmax[1] += 15; } else { // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch ent->v.absmin[0] -= 1; ent->v.absmin[1] -= 1; ent->v.absmin[2] -= 1; ent->v.absmax[0] += 1; ent->v.absmax[1] += 1; ent->v.absmax[2] += 1; } // link to PVS leafs ent->num_leafs = 0; if (ent->v.modelindex) SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); if (ent->v.solid == SOLID_NOT) return; // find the first node that the ent's box crosses node = sv_areanodes; while (1) { if (node->axis == -1) break; if (ent->v.absmin[node->axis] > node->dist) node = node->children[0]; else if (ent->v.absmax[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in if (ent->v.solid == SOLID_TRIGGER) InsertLinkBefore (&ent->area, &node->trigger_edicts); else InsertLinkBefore (&ent->area, &node->solid_edicts); // if touch_triggers, touch all entities at this node and decend for more if (touch_triggers) SV_TouchLinks ( ent, sv_areanodes ); } /* =============================================================================== POINT TESTING IN HULLS =============================================================================== */ /* ================== SV_HullPointContents ================== */ int SV_HullPointContents (hull_t *hull, int num, vec3_t p) { float d; mclipnode_t *node; //johnfitz -- was dclipnode_t mplane_t *plane; while (num >= 0) { if (num < hull->firstclipnode || num > hull->lastclipnode) Sys_Error ("SV_HullPointContents: bad node number"); node = hull->clipnodes + num; plane = hull->planes + node->planenum; if (plane->type < 3) d = p[plane->type] - plane->dist; else d = DotProduct (plane->normal, p) - plane->dist; if (d < 0) num = node->children[1]; else num = node->children[0]; } return num; } /* ================== SV_PointContents ================== */ int SV_PointContents (vec3_t p) { int cont; cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) cont = CONTENTS_WATER; return cont; } int SV_TruePointContents (vec3_t p) { return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); } //=========================================================================== /* ============ SV_TestEntityPosition This could be a lot more efficient... ============ */ edict_t *SV_TestEntityPosition (edict_t *ent) { trace_t trace; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent); if (trace.startsolid) return sv.edicts; return NULL; } /* =============================================================================== LINE TESTING IN HULLS =============================================================================== */ /* ================== SV_RecursiveHullCheck ================== */ qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) { mclipnode_t *node; //johnfitz -- was dclipnode_t mplane_t *plane; float t1, t2; float frac; int i; vec3_t mid; int side; float midf; // check for empty if (num < 0) { if (num != CONTENTS_SOLID) { trace->allsolid = false; if (num == CONTENTS_EMPTY) trace->inopen = true; else trace->inwater = true; } else trace->startsolid = true; return true; // empty } if (num < hull->firstclipnode || num > hull->lastclipnode) Sys_Error ("SV_RecursiveHullCheck: bad node number"); // // find the point distances // node = hull->clipnodes + num; plane = hull->planes + node->planenum; if (plane->type < 3) { t1 = p1[plane->type] - plane->dist; t2 = p2[plane->type] - plane->dist; } else { t1 = DotProduct (plane->normal, p1) - plane->dist; t2 = DotProduct (plane->normal, p2) - plane->dist; } #if 1 if (t1 >= 0 && t2 >= 0) return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); if (t1 < 0 && t2 < 0) return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); #else if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) ) return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) ) return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); #endif // put the crosspoint DIST_EPSILON pixels on the near side if (t1 < 0) frac = (t1 + DIST_EPSILON)/(t1-t2); else frac = (t1 - DIST_EPSILON)/(t1-t2); if (frac < 0) frac = 0; if (frac > 1) frac = 1; midf = p1f + (p2f - p1f)*frac; for (i=0 ; i<3 ; i++) mid[i] = p1[i] + frac*(p2[i] - p1[i]); side = (t1 < 0); // move up to the node if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) ) return false; #ifdef PARANOID if (SV_HullPointContents (sv_hullmodel, mid, node->children[side]) == CONTENTS_SOLID) { Con_Printf ("mid PointInHullSolid\n"); return false; } #endif if (SV_HullPointContents (hull, node->children[side^1], mid) != CONTENTS_SOLID) // go past the node return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace); if (trace->allsolid) return false; // never got out of the solid area //================== // the other side of the node is solid, this is the impact point //================== if (!side) { VectorCopy (plane->normal, trace->plane.normal); trace->plane.dist = plane->dist; } else { VectorSubtract (vec3_origin, plane->normal, trace->plane.normal); trace->plane.dist = -plane->dist; } while (SV_HullPointContents (hull, hull->firstclipnode, mid) == CONTENTS_SOLID) { // shouldn't really happen, but does occasionally frac -= 0.1; if (frac < 0) { trace->fraction = midf; VectorCopy (mid, trace->endpos); Con_DPrintf ("backup past 0\n"); return false; } midf = p1f + (p2f - p1f)*frac; for (i=0 ; i<3 ; i++) mid[i] = p1[i] + frac*(p2[i] - p1[i]); } trace->fraction = midf; VectorCopy (mid, trace->endpos); return false; } /* ================== SV_ClipMoveToEntity Handles selection or creation of a clipping hull, and offseting (and eventually rotation) of the end points ================== */ trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) { trace_t trace; vec3_t offset; vec3_t start_l, end_l; hull_t *hull; // fill in a default trace memset (&trace, 0, sizeof(trace_t)); trace.fraction = 1; trace.allsolid = true; VectorCopy (end, trace.endpos); // get the clipping hull hull = SV_HullForEntity (ent, mins, maxs, offset); VectorSubtract (start, offset, start_l); VectorSubtract (end, offset, end_l); // trace a line through the apropriate clipping hull SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); // fix trace up by the offset if (trace.fraction != 1) VectorAdd (trace.endpos, offset, trace.endpos); // did we clip the move? if (trace.fraction < 1 || trace.startsolid ) trace.ent = ent; return trace; } //=========================================================================== /* ==================== SV_ClipToLinks Mins and maxs enclose the entire area swept by the move ==================== */ void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip ) { link_t *l, *next; edict_t *touch; trace_t trace; // touch linked edicts for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next) { next = l->next; touch = EDICT_FROM_AREA(l); if (touch->v.solid == SOLID_NOT) continue; if (touch == clip->passedict) continue; if (touch->v.solid == SOLID_TRIGGER) Sys_Error ("Trigger in clipping list"); if (clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP) continue; if (clip->boxmins[0] > touch->v.absmax[0] || clip->boxmins[1] > touch->v.absmax[1] || clip->boxmins[2] > touch->v.absmax[2] || clip->boxmaxs[0] < touch->v.absmin[0] || clip->boxmaxs[1] < touch->v.absmin[1] || clip->boxmaxs[2] < touch->v.absmin[2] ) continue; if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0]) continue; // points never interact // might intersect, so do an exact clip if (clip->trace.allsolid) return; if (clip->passedict) { if (PROG_TO_EDICT(touch->v.owner) == clip->passedict) continue; // don't clip against own missiles if (PROG_TO_EDICT(clip->passedict->v.owner) == touch) continue; // don't clip against owner } if ((int)touch->v.flags & FL_MONSTER) trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end); else trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) { trace.ent = touch; if (clip->trace.startsolid) { clip->trace = trace; clip->trace.startsolid = true; } else clip->trace = trace; } else if (trace.startsolid) clip->trace.startsolid = true; } // recurse down both sides if (node->axis == -1) return; if ( clip->boxmaxs[node->axis] > node->dist ) SV_ClipToLinks ( node->children[0], clip ); if ( clip->boxmins[node->axis] < node->dist ) SV_ClipToLinks ( node->children[1], clip ); } /* ================== SV_MoveBounds ================== */ void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs) { #if 0 // debug to test against everything boxmins[0] = boxmins[1] = boxmins[2] = -9999; boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999; #else int i; for (i=0 ; i<3 ; i++) { if (end[i] > start[i]) { boxmins[i] = start[i] + mins[i] - 1; boxmaxs[i] = end[i] + maxs[i] + 1; } else { boxmins[i] = end[i] + mins[i] - 1; boxmaxs[i] = start[i] + maxs[i] + 1; } } #endif } /* ================== SV_Move ================== */ trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict) { moveclip_t clip; int i; memset ( &clip, 0, sizeof ( moveclip_t ) ); // clip to world clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end ); clip.start = start; clip.end = end; clip.mins = mins; clip.maxs = maxs; clip.type = type; clip.passedict = passedict; if (type == MOVE_MISSILE) { for (i=0 ; i<3 ; i++) { clip.mins2[i] = -15; clip.maxs2[i] = 15; } } else { VectorCopy (mins, clip.mins2); VectorCopy (maxs, clip.maxs2); } // create the bounding box of the entire move SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs ); // clip to entities SV_ClipToLinks ( sv_areanodes, &clip ); return clip.trace; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_mesh.c�������������������������������������������������������������������0000644�0000000�0000000�00000035134�12577611311�015313� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // gl_mesh.c: triangle model functions #include "quakedef.h" /* ================================================================= ALIAS MODEL DISPLAY LIST GENERATION ================================================================= */ qmodel_t *aliasmodel; aliashdr_t *paliashdr; int used[8192]; // qboolean // the command list holds counts and s/t values that are valid for // every frame int commands[8192]; int numcommands; // all frames will have their vertexes rearranged and expanded // so they are in the order expected by the command list int vertexorder[8192]; int numorder; int allverts, alltris; int stripverts[128]; int striptris[128]; int stripcount; /* ================ StripLength ================ */ int StripLength (int starttri, int startv) { int m1, m2; int j; mtriangle_t *last, *check; int k; used[starttri] = 2; last = &triangles[starttri]; stripverts[0] = last->vertindex[(startv)%3]; stripverts[1] = last->vertindex[(startv+1)%3]; stripverts[2] = last->vertindex[(startv+2)%3]; striptris[0] = starttri; stripcount = 1; m1 = last->vertindex[(startv+2)%3]; m2 = last->vertindex[(startv+1)%3]; // look for a matching triangle nexttri: for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++) { if (check->facesfront != last->facesfront) continue; for (k=0 ; k<3 ; k++) { if (check->vertindex[k] != m1) continue; if (check->vertindex[ (k+1)%3 ] != m2) continue; // this is the next part of the fan // if we can't use this triangle, this tristrip is done if (used[j]) goto done; // the new edge if (stripcount & 1) m2 = check->vertindex[ (k+2)%3 ]; else m1 = check->vertindex[ (k+2)%3 ]; stripverts[stripcount+2] = check->vertindex[ (k+2)%3 ]; striptris[stripcount] = j; stripcount++; used[j] = 2; goto nexttri; } } done: // clear the temp used flags for (j=starttri+1 ; j<pheader->numtris ; j++) if (used[j] == 2) used[j] = 0; return stripcount; } /* =========== FanLength =========== */ int FanLength (int starttri, int startv) { int m1, m2; int j; mtriangle_t *last, *check; int k; used[starttri] = 2; last = &triangles[starttri]; stripverts[0] = last->vertindex[(startv)%3]; stripverts[1] = last->vertindex[(startv+1)%3]; stripverts[2] = last->vertindex[(startv+2)%3]; striptris[0] = starttri; stripcount = 1; m1 = last->vertindex[(startv+0)%3]; m2 = last->vertindex[(startv+2)%3]; // look for a matching triangle nexttri: for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++) { if (check->facesfront != last->facesfront) continue; for (k=0 ; k<3 ; k++) { if (check->vertindex[k] != m1) continue; if (check->vertindex[ (k+1)%3 ] != m2) continue; // this is the next part of the fan // if we can't use this triangle, this tristrip is done if (used[j]) goto done; // the new edge m2 = check->vertindex[ (k+2)%3 ]; stripverts[stripcount+2] = m2; striptris[stripcount] = j; stripcount++; used[j] = 2; goto nexttri; } } done: // clear the temp used flags for (j=starttri+1 ; j<pheader->numtris ; j++) if (used[j] == 2) used[j] = 0; return stripcount; } /* ================ BuildTris Generate a list of trifans or strips for the model, which holds for all frames ================ */ void BuildTris (void) { int i, j, k; int startv; float s, t; int len, bestlen, besttype; int bestverts[1024]; int besttris[1024]; int type; // // build tristrips // numorder = 0; numcommands = 0; memset (used, 0, sizeof(used)); for (i = 0; i < pheader->numtris; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; bestlen = 0; besttype = 0; for (type = 0 ; type < 2 ; type++) // type = 1; { for (startv = 0; startv < 3; startv++) { if (type == 1) len = StripLength (i, startv); else len = FanLength (i, startv); if (len > bestlen) { besttype = type; bestlen = len; for (j = 0; j < bestlen+2; j++) bestverts[j] = stripverts[j]; for (j = 0; j < bestlen; j++) besttris[j] = striptris[j]; } } } // mark the tris on the best strip as used for (j = 0; j < bestlen; j++) used[besttris[j]] = 1; if (besttype == 1) commands[numcommands++] = (bestlen+2); else commands[numcommands++] = -(bestlen+2); for (j = 0; j < bestlen+2; j++) { int tmp; // emit a vertex into the reorder buffer k = bestverts[j]; vertexorder[numorder++] = k; // emit s/t coords into the commands stream s = stverts[k].s; t = stverts[k].t; if (!triangles[besttris[0]].facesfront && stverts[k].onseam) s += pheader->skinwidth / 2; // on back side s = (s + 0.5) / pheader->skinwidth; t = (t + 0.5) / pheader->skinheight; // *(float *)&commands[numcommands++] = s; // *(float *)&commands[numcommands++] = t; // NOTE: 4 == sizeof(int) // == sizeof(float) memcpy (&tmp, &s, 4); commands[numcommands++] = tmp; memcpy (&tmp, &t, 4); commands[numcommands++] = tmp; } } commands[numcommands++] = 0; // end of list marker Con_DPrintf2 ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands); allverts += numorder; alltris += pheader->numtris; } static void GL_MakeAliasModelDisplayLists_VBO (void); static void GLMesh_LoadVertexBuffer (qmodel_t *m, const aliashdr_t *hdr); /* ================ GL_MakeAliasModelDisplayLists ================ */ void GL_MakeAliasModelDisplayLists (qmodel_t *m, aliashdr_t *hdr) { int i, j; int *cmds; trivertx_t *verts; float hscale, vscale; //johnfitz -- padded skins int count; //johnfitz -- precompute texcoords for padded skins int *loadcmds; //johnfitz //johnfitz -- padded skins hscale = (float)hdr->skinwidth/(float)TexMgr_PadConditional(hdr->skinwidth); vscale = (float)hdr->skinheight/(float)TexMgr_PadConditional(hdr->skinheight); //johnfitz aliasmodel = m; paliashdr = hdr; // (aliashdr_t *)Mod_Extradata (m); //johnfitz -- generate meshes Con_DPrintf2 ("meshing %s...\n",m->name); BuildTris (); // save the data out paliashdr->poseverts = numorder; cmds = (int *) Hunk_Alloc (numcommands * 4); paliashdr->commands = (byte *)cmds - (byte *)paliashdr; //johnfitz -- precompute texcoords for padded skins loadcmds = commands; while(1) { *cmds++ = count = *loadcmds++; if (!count) break; if (count < 0) count = -count; do { *(float *)cmds++ = hscale * (*(float *)loadcmds++); *(float *)cmds++ = vscale * (*(float *)loadcmds++); } while (--count); } //johnfitz verts = (trivertx_t *) Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts * sizeof(trivertx_t)); paliashdr->posedata = (byte *)verts - (byte *)paliashdr; for (i=0 ; i<paliashdr->numposes ; i++) for (j=0 ; j<numorder ; j++) *verts++ = poseverts[i][vertexorder[j]]; // ericw GL_MakeAliasModelDisplayLists_VBO (); } unsigned int r_meshindexbuffer = 0; unsigned int r_meshvertexbuffer = 0; /* ================ GL_MakeAliasModelDisplayLists_VBO Saves data needed to build the VBO for this model on the hunk. Afterwards this is copied to Mod_Extradata. Original code by MH from RMQEngine ================ */ void GL_MakeAliasModelDisplayLists_VBO (void) { int i, j; int maxverts_vbo; trivertx_t *verts; unsigned short *indexes; aliasmesh_t *desc; if (!gl_glsl_alias_able) return; // first, copy the verts onto the hunk verts = (trivertx_t *) Hunk_Alloc (paliashdr->numposes * paliashdr->numverts * sizeof(trivertx_t)); paliashdr->vertexes = (byte *)verts - (byte *)paliashdr; for (i=0 ; i<paliashdr->numposes ; i++) for (j=0 ; j<paliashdr->numverts ; j++) verts[i*paliashdr->numverts + j] = poseverts[i][j]; // there can never be more than this number of verts and we just put them all on the hunk maxverts_vbo = pheader->numtris * 3; desc = (aliasmesh_t *) Hunk_Alloc (sizeof (aliasmesh_t) * maxverts_vbo); // there will always be this number of indexes indexes = (unsigned short *) Hunk_Alloc (sizeof (unsigned short) * maxverts_vbo); pheader->indexes = (intptr_t) indexes - (intptr_t) pheader; pheader->meshdesc = (intptr_t) desc - (intptr_t) pheader; pheader->numindexes = 0; pheader->numverts_vbo = 0; for (i = 0; i < pheader->numtris; i++) { for (j = 0; j < 3; j++) { int v; // index into hdr->vertexes unsigned short vertindex = triangles[i].vertindex[j]; // basic s/t coords int s = stverts[vertindex].s; int t = stverts[vertindex].t; // check for back side and adjust texcoord s if (!triangles[i].facesfront && stverts[vertindex].onseam) s += pheader->skinwidth / 2; // see does this vert already exist for (v = 0; v < pheader->numverts_vbo; v++) { // it could use the same xyz but have different s and t if (desc[v].vertindex == vertindex && (int) desc[v].st[0] == s && (int) desc[v].st[1] == t) { // exists; emit an index for it indexes[pheader->numindexes++] = v; // no need to check any more break; } } if (v == pheader->numverts_vbo) { // doesn't exist; emit a new vert and index indexes[pheader->numindexes++] = pheader->numverts_vbo; desc[pheader->numverts_vbo].vertindex = vertindex; desc[pheader->numverts_vbo].st[0] = s; desc[pheader->numverts_vbo++].st[1] = t; } } } // upload immediately GLMesh_LoadVertexBuffer (aliasmodel, pheader); } #define NUMVERTEXNORMALS 162 extern float r_avertexnormals[NUMVERTEXNORMALS][3]; /* ================ GLMesh_LoadVertexBuffer Upload the given alias model's mesh to a VBO Original code by MH from RMQEngine ================ */ static void GLMesh_LoadVertexBuffer (qmodel_t *m, const aliashdr_t *hdr) { int totalvbosize = 0; const aliasmesh_t *desc; const short *indexes; const trivertx_t *trivertexes; byte *vbodata; int f; if (!gl_glsl_alias_able) return; // count the sizes we need // ericw -- RMQEngine stored these vbo*ofs values in aliashdr_t, but we must not // mutate Mod_Extradata since it might be reloaded from disk, so I moved them to qmodel_t // (test case: roman1.bsp from arwop, 64mb heap) m->vboindexofs = 0; m->vboxyzofs = 0; totalvbosize += (hdr->numposes * hdr->numverts_vbo * sizeof (meshxyz_t)); // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm m->vbostofs = totalvbosize; totalvbosize += (hdr->numverts_vbo * sizeof (meshst_t)); if (!hdr->numindexes) return; if (!totalvbosize) return; // grab the pointers to data in the extradata desc = (aliasmesh_t *) ((byte *) hdr + hdr->meshdesc); indexes = (short *) ((byte *) hdr + hdr->indexes); trivertexes = (trivertx_t *) ((byte *)hdr + hdr->vertexes); // upload indices buffer GL_DeleteBuffersFunc (1, &m->meshindexesvbo); GL_GenBuffersFunc (1, &m->meshindexesvbo); GL_BindBufferFunc (GL_ELEMENT_ARRAY_BUFFER, m->meshindexesvbo); GL_BufferDataFunc (GL_ELEMENT_ARRAY_BUFFER, hdr->numindexes * sizeof (unsigned short), indexes, GL_STATIC_DRAW); // create the vertex buffer (empty) vbodata = (byte *) malloc(totalvbosize); memset(vbodata, 0, totalvbosize); // fill in the vertices at the start of the buffer for (f = 0; f < hdr->numposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm { int v; meshxyz_t *xyz = (meshxyz_t *) (vbodata + (f * hdr->numverts_vbo * sizeof (meshxyz_t))); const trivertx_t *tv = trivertexes + (hdr->numverts * f); for (v = 0; v < hdr->numverts_vbo; v++) { trivertx_t trivert = tv[desc[v].vertindex]; xyz[v].xyz[0] = trivert.v[0]; xyz[v].xyz[1] = trivert.v[1]; xyz[v].xyz[2] = trivert.v[2]; xyz[v].xyz[3] = 1; // need w 1 for 4 byte vertex compression // map the normal coordinates in [-1..1] to [-127..127] and store in an unsigned char. // this introduces some error (less than 0.004), but the normals were very coarse // to begin with xyz[v].normal[0] = 127 * r_avertexnormals[trivert.lightnormalindex][0]; xyz[v].normal[1] = 127 * r_avertexnormals[trivert.lightnormalindex][1]; xyz[v].normal[2] = 127 * r_avertexnormals[trivert.lightnormalindex][2]; xyz[v].normal[3] = 0; // unused; for 4-byte alignment } } // fill in the ST coords at the end of the buffer { meshst_t *st; float hscale, vscale; //johnfitz -- padded skins hscale = (float)hdr->skinwidth/(float)TexMgr_PadConditional(hdr->skinwidth); vscale = (float)hdr->skinheight/(float)TexMgr_PadConditional(hdr->skinheight); //johnfitz st = (meshst_t *) (vbodata + m->vbostofs); for (f = 0; f < hdr->numverts_vbo; f++) { st[f].st[0] = hscale * ((float) desc[f].st[0] + 0.5f) / (float) hdr->skinwidth; st[f].st[1] = vscale * ((float) desc[f].st[1] + 0.5f) / (float) hdr->skinheight; } } // upload vertexes buffer GL_DeleteBuffersFunc (1, &m->meshvbo); GL_GenBuffersFunc (1, &m->meshvbo); GL_BindBufferFunc (GL_ARRAY_BUFFER, m->meshvbo); GL_BufferDataFunc (GL_ARRAY_BUFFER, totalvbosize, vbodata, GL_STATIC_DRAW); free (vbodata); // invalidate the cached bindings GL_ClearBufferBindings (); } /* ================ GLMesh_LoadVertexBuffers Loop over all precached alias models, and upload each one to a VBO. ================ */ void GLMesh_LoadVertexBuffers (void) { int j; qmodel_t *m; const aliashdr_t *hdr; if (!gl_glsl_alias_able) return; for (j = 1; j < MAX_MODELS; j++) { if (!(m = cl.model_precache[j])) break; if (m->type != mod_alias) continue; hdr = (const aliashdr_t *) Mod_Extradata (m); GLMesh_LoadVertexBuffer (m, hdr); } } /* ================ GLMesh_DeleteVertexBuffers Delete VBOs for all loaded alias models ================ */ void GLMesh_DeleteVertexBuffers (void) { int j; qmodel_t *m; if (!gl_glsl_alias_able) return; for (j = 1; j < MAX_MODELS; j++) { if (!(m = cl.model_precache[j])) break; if (m->type != mod_alias) continue; GL_DeleteBuffersFunc (1, &m->meshvbo); m->meshvbo = 0; GL_DeleteBuffersFunc (1, &m->meshindexesvbo); m->meshindexesvbo = 0; } GL_ClearBufferBindings (); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_mix.c�������������������������������������������������������������������0000644�0000000�0000000�00000031121�12407762022�015324� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2011 O. Sezer <sezero@users.sourceforge.net> Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // snd_mix.c -- portable code to mix sounds for snd_dma.c #include "quakedef.h" #define PAINTBUFFER_SIZE 2048 portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; int snd_scaletable[32][256]; int *snd_p, snd_linear_count; short *snd_out; static int snd_vol; static void Snd_WriteLinearBlastStereo16 (void) { int i; int val; for (i = 0; i < snd_linear_count; i += 2) { val = snd_p[i] >> 8; if (val > 0x7fff) snd_out[i] = 0x7fff; else if (val < (short)0x8000) snd_out[i] = (short)0x8000; else snd_out[i] = val; val = snd_p[i+1] >> 8; if (val > 0x7fff) snd_out[i+1] = 0x7fff; else if (val < (short)0x8000) snd_out[i+1] = (short)0x8000; else snd_out[i+1] = val; } } static void S_TransferStereo16 (int endtime) { int lpos; int lpaintedtime; snd_p = (int *) paintbuffer; lpaintedtime = paintedtime; while (lpaintedtime < endtime) { // handle recirculating buffer issues lpos = lpaintedtime & ((shm->samples >> 1) - 1); snd_out = (short *)shm->buffer + (lpos << 1); snd_linear_count = (shm->samples >> 1) - lpos; if (lpaintedtime + snd_linear_count > endtime) snd_linear_count = endtime - lpaintedtime; snd_linear_count <<= 1; // write a linear blast of samples Snd_WriteLinearBlastStereo16 (); snd_p += snd_linear_count; lpaintedtime += (snd_linear_count >> 1); } } static void S_TransferPaintBuffer (int endtime) { int out_idx, out_mask; int count, step, val; int *p; if (shm->samplebits == 16 && shm->channels == 2) { S_TransferStereo16 (endtime); return; } p = (int *) paintbuffer; count = (endtime - paintedtime) * shm->channels; out_mask = shm->samples - 1; out_idx = paintedtime * shm->channels & out_mask; step = 3 - shm->channels; if (shm->samplebits == 16) { short *out = (short *)shm->buffer; while (count--) { val = *p >> 8; p+= step; if (val > 0x7fff) val = 0x7fff; else if (val < (short)0x8000) val = (short)0x8000; out[out_idx] = val; out_idx = (out_idx + 1) & out_mask; } } else if (shm->samplebits == 8 && !shm->signed8) { unsigned char *out = shm->buffer; while (count--) { val = *p >> 8; p+= step; if (val > 0x7fff) val = 0x7fff; else if (val < (short)0x8000) val = (short)0x8000; out[out_idx] = (val >> 8) + 128; out_idx = (out_idx + 1) & out_mask; } } else if (shm->samplebits == 8) /* S8 format, e.g. with Amiga AHI */ { signed char *out = (signed char *) shm->buffer; while (count--) { val = *p >> 8; p+= step; if (val > 0x7fff) val = 0x7fff; else if (val < (short)0x8000) val = (short)0x8000; out[out_idx] = (val >> 8); out_idx = (out_idx + 1) & out_mask; } } } /* ============== S_MakeBlackmanWindowKernel Makes a lowpass filter kernel, from equation 16-4 in "The Scientist and Engineer's Guide to Digital Signal Processing" M is the kernel size (not counting the center point), must be even kernel has room for M+1 floats f_c is the filter cutoff frequency, as a fraction of the samplerate ============== */ static void S_MakeBlackmanWindowKernel(float *kernel, int M, float f_c) { int i; for (i = 0; i <= M; i++) { if (i == M/2) { kernel[i] = 2 * M_PI * f_c; } else { kernel[i] = ( sin(2 * M_PI * f_c * (i - M/2.0)) / (i - (M/2.0)) ) * (0.42 - 0.5*cos(2 * M_PI * i / (double)M) + 0.08*cos(4 * M_PI * i / (double)M) ); } } // normalize the kernel so all of the values sum to 1 { float sum = 0; for (i = 0; i <= M; i++) { sum += kernel[i]; } for (i = 0; i <= M; i++) { kernel[i] /= sum; } } } typedef struct { float *memory; // kernelsize floats float *kernel; // kernelsize floats int kernelsize; // M+1, rounded up to be a multiple of 16 int M; // M value used to make kernel, even int parity; // 0-3 float f_c; // cutoff frequency, [0..1], fraction of sample rate } filter_t; static void S_UpdateFilter(filter_t *filter, int M, float f_c) { if (filter->f_c != f_c || filter->M != M) { if (filter->memory != NULL) free(filter->memory); if (filter->kernel != NULL) free(filter->kernel); filter->M = M; filter->f_c = f_c; filter->parity = 0; // M + 1 rounded up to the next multiple of 16 filter->kernelsize = (M + 1) + 16 - ((M + 1) % 16); filter->memory = (float *) calloc(filter->kernelsize, sizeof(float)); filter->kernel = (float *) calloc(filter->kernelsize, sizeof(float)); S_MakeBlackmanWindowKernel(filter->kernel, M, f_c); } } /* ============== S_ApplyFilter Lowpass-filter the given buffer containing 44100Hz audio. As an optimization, it decimates the audio to 11025Hz (setting every sample position that's not a multiple of 4 to 0), then convoluting with the filter kernel is 4x faster, because we can skip 3/4 of the input samples that are known to be 0 and skip 3/4 of the filter kernel. ============== */ static void S_ApplyFilter(filter_t *filter, int *data, int stride, int count) { int i, j; float *input; const int kernelsize = filter->kernelsize; const float *kernel = filter->kernel; int parity; input = (float *) malloc(sizeof(float) * (filter->kernelsize + count)); // set up the input buffer // memory holds the previous filter->kernelsize samples of input. memcpy(input, filter->memory, filter->kernelsize * sizeof(float)); for (i=0; i<count; i++) { input[filter->kernelsize+i] = data[i * stride] / (32768.0 * 256.0); } // copy out the last filter->kernelsize samples to 'memory' for next time memcpy(filter->memory, input + count, filter->kernelsize * sizeof(float)); // apply the filter parity = filter->parity; for (i=0; i<count; i++) { const float *input_plus_i = input + i; float val[4] = {0, 0, 0, 0}; for (j = (4 - parity) % 4; j < kernelsize; j+=16) { val[0] += kernel[j] * input_plus_i[j]; val[1] += kernel[j+4] * input_plus_i[j+4]; val[2] += kernel[j+8] * input_plus_i[j+8]; val[3] += kernel[j+12] * input_plus_i[j+12]; } // 4.0 factor is to increase volume by 12 dB; this is to make up the // volume drop caused by the zero-filling this filter does. data[i * stride] = (val[0] + val[1] + val[2] + val[3]) * (32768.0 * 256.0 * 4.0); parity = (parity + 1) % 4; } filter->parity = parity; free(input); } /* ============== S_LowpassFilter lowpass filters 24-bit integer samples in 'data' (stored in 32-bit ints). assumes 44100Hz sample rate, and lowpasses at around 5kHz memory should be a zero-filled filter_t struct ============== */ static void S_LowpassFilter(int *data, int stride, int count, filter_t *memory) { int M; float bw, f_c; switch ((int)snd_filterquality.value) { case 1: M = 126; bw = 0.900; break; case 2: M = 150; bw = 0.915; break; case 3: M = 174; bw = 0.930; break; case 4: M = 198; bw = 0.945; break; case 5: default: M = 222; bw = 0.960; break; } f_c = (bw * 11025 / 2.0) / 44100.0; S_UpdateFilter(memory, M, f_c); S_ApplyFilter(memory, data, stride, count); } /* =============================================================================== CHANNEL MIXING =============================================================================== */ static void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int paintbufferstart); static void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int paintbufferstart); void S_PaintChannels (int endtime) { int i; int end, ltime, count; channel_t *ch; sfxcache_t *sc; snd_vol = sfxvolume.value * 256; while (paintedtime < endtime) { // if paintbuffer is smaller than DMA buffer end = endtime; if (endtime - paintedtime > PAINTBUFFER_SIZE) end = paintedtime + PAINTBUFFER_SIZE; // clear the paint buffer memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t)); // paint in the channels. ch = snd_channels; for (i = 0; i < total_channels; i++, ch++) { if (!ch->sfx) continue; if (!ch->leftvol && !ch->rightvol) continue; sc = S_LoadSound (ch->sfx); if (!sc) continue; ltime = paintedtime; while (ltime < end) { // paint up to end if (ch->end < end) count = ch->end - ltime; else count = end - ltime; if (count > 0) { // the last param to SND_PaintChannelFrom is the index // to start painting to in the paintbuffer, usually 0. if (sc->width == 1) SND_PaintChannelFrom8(ch, sc, count, ltime - paintedtime); else SND_PaintChannelFrom16(ch, sc, count, ltime - paintedtime); ltime += count; } // if at end of loop, restart if (ltime >= ch->end) { if (sc->loopstart >= 0) { ch->pos = sc->loopstart; ch->end = ltime + sc->length - ch->pos; } else { // channel just stopped ch->sfx = NULL; break; } } } } // clip each sample to 0dB, then reduce by 6dB (to leave some headroom for // the lowpass filter and the music). the lowpass will smooth out the // clipping for (i=0; i<end-paintedtime; i++) { paintbuffer[i].left = CLAMP(-32768 << 8, paintbuffer[i].left, 32767 << 8) >> 1; paintbuffer[i].right = CLAMP(-32768 << 8, paintbuffer[i].right, 32767 << 8) >> 1; } // apply a lowpass filter if (sndspeed.value == 11025 && shm->speed == 44100) { static filter_t memory_l, memory_r; S_LowpassFilter((int *)paintbuffer, 2, end - paintedtime, &memory_l); S_LowpassFilter(((int *)paintbuffer) + 1, 2, end - paintedtime, &memory_r); } // paint in the music if (s_rawend >= paintedtime) { // copy from the streaming sound source int s; int stop; stop = (end < s_rawend) ? end : s_rawend; for (i = paintedtime; i < stop; i++) { s = i & (MAX_RAW_SAMPLES - 1); // lower music by 6db to match sfx paintbuffer[i - paintedtime].left += s_rawsamples[s].left >> 1; paintbuffer[i - paintedtime].right += s_rawsamples[s].right >> 1; } // if (i != end) // Con_Printf ("partial stream\n"); // else // Con_Printf ("full stream\n"); } // transfer out according to DMA format S_TransferPaintBuffer(end); paintedtime = end; } } void SND_InitScaletable (void) { int i, j; int scale; for (i = 0; i < 32; i++) { scale = i * 8 * 256 * sfxvolume.value; for (j = 0; j < 256; j++) { /* When compiling with gcc-4.1.0 at optimisations O1 and higher, the tricky signed char type conversion is not guaranteed. Therefore we explicity calculate the signed value from the index as required. From Kevin Shanahan. See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26719 */ // snd_scaletable[i][j] = ((signed char)j) * scale; snd_scaletable[i][j] = ((j < 128) ? j : j - 256) * scale; } } } static void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int paintbufferstart) { int data; int *lscale, *rscale; unsigned char *sfx; int i; if (ch->leftvol > 255) ch->leftvol = 255; if (ch->rightvol > 255) ch->rightvol = 255; lscale = snd_scaletable[ch->leftvol >> 3]; rscale = snd_scaletable[ch->rightvol >> 3]; sfx = (unsigned char *)sc->data + ch->pos; for (i = 0; i < count; i++) { data = sfx[i]; paintbuffer[paintbufferstart + i].left += lscale[data]; paintbuffer[paintbufferstart + i].right += rscale[data]; } ch->pos += count; } static void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int paintbufferstart) { int data; int left, right; int leftvol, rightvol; signed short *sfx; int i; leftvol = ch->leftvol * snd_vol; rightvol = ch->rightvol * snd_vol; leftvol >>= 8; rightvol >>= 8; sfx = (signed short *)sc->data + ch->pos; for (i = 0; i < count; i++) { data = sfx[i]; // this was causing integer overflow as observed in quakespasm // with the warpspasm mod moved >>8 to left/right volume above. // left = (data * leftvol) >> 8; // right = (data * rightvol) >> 8; left = data * leftvol; right = data * rightvol; paintbuffer[paintbufferstart + i].left += left; paintbuffer[paintbufferstart + i].right += right; } ch->pos += count; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_model.c������������������������������������������������������������������0000644�0000000�0000000�00000217163�12577611311�015463� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // models.c -- model loading and caching // models are the only shared resource between a client and server running // on the same machine. #include "quakedef.h" qmodel_t *loadmodel; char loadname[32]; // for hunk tags void Mod_LoadSpriteModel (qmodel_t *mod, void *buffer); void Mod_LoadBrushModel (qmodel_t *mod, void *buffer); void Mod_LoadAliasModel (qmodel_t *mod, void *buffer); qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash); cvar_t external_ents = {"external_ents", "1", CVAR_ARCHIVE}; byte mod_novis[MAX_MAP_LEAFS/8]; #define MAX_MOD_KNOWN 2048 /*johnfitz -- was 512 */ qmodel_t mod_known[MAX_MOD_KNOWN]; int mod_numknown; texture_t *r_notexture_mip; //johnfitz -- moved here from r_main.c texture_t *r_notexture_mip2; //johnfitz -- used for non-lightmapped surfs with a missing texture /* =============== Mod_Init =============== */ void Mod_Init (void) { Cvar_RegisterVariable (&gl_subdivide_size); Cvar_RegisterVariable (&external_ents); memset (mod_novis, 0xff, sizeof(mod_novis)); //johnfitz -- create notexture miptex r_notexture_mip = (texture_t *) Hunk_AllocName (sizeof(texture_t), "r_notexture_mip"); strcpy (r_notexture_mip->name, "notexture"); r_notexture_mip->height = r_notexture_mip->width = 32; r_notexture_mip2 = (texture_t *) Hunk_AllocName (sizeof(texture_t), "r_notexture_mip2"); strcpy (r_notexture_mip2->name, "notexture2"); r_notexture_mip2->height = r_notexture_mip2->width = 32; //johnfitz } /* =============== Mod_Extradata Caches the data if needed =============== */ void *Mod_Extradata (qmodel_t *mod) { void *r; r = Cache_Check (&mod->cache); if (r) return r; Mod_LoadModel (mod, true); if (!mod->cache.data) Sys_Error ("Mod_Extradata: caching failed"); return mod->cache.data; } /* =============== Mod_PointInLeaf =============== */ mleaf_t *Mod_PointInLeaf (vec3_t p, qmodel_t *model) { mnode_t *node; float d; mplane_t *plane; if (!model || !model->nodes) Sys_Error ("Mod_PointInLeaf: bad model"); node = model->nodes; while (1) { if (node->contents < 0) return (mleaf_t *)node; plane = node->plane; d = DotProduct (p,plane->normal) - plane->dist; if (d > 0) node = node->children[0]; else node = node->children[1]; } return NULL; // never reached } /* =================== Mod_DecompressVis =================== */ byte *Mod_DecompressVis (byte *in, qmodel_t *model) { static byte decompressed[MAX_MAP_LEAFS/8]; int c; byte *out; int row; row = (model->numleafs+7)>>3; out = decompressed; #if 0 memcpy (out, in, row); #else if (!in) { // no vis info, so make all visible while (row) { *out++ = 0xff; row--; } return decompressed; } do { if (*in) { *out++ = *in++; continue; } c = in[1]; in += 2; while (c) { *out++ = 0; c--; } } while (out - decompressed < row); #endif return decompressed; } byte *Mod_LeafPVS (mleaf_t *leaf, qmodel_t *model) { if (leaf == model->leafs) return mod_novis; return Mod_DecompressVis (leaf->compressed_vis, model); } /* =================== Mod_ClearAll =================== */ void Mod_ClearAll (void) { int i; qmodel_t *mod; for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) if (mod->type != mod_alias) { mod->needload = true; TexMgr_FreeTexturesForOwner (mod); //johnfitz } } void Mod_ResetAll (void) { int i; qmodel_t *mod; //ericw -- free alias model VBOs GLMesh_DeleteVertexBuffers (); for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) { if (!mod->needload) //otherwise Mod_ClearAll() did it already TexMgr_FreeTexturesForOwner (mod); memset(mod, 0, sizeof(qmodel_t)); } mod_numknown = 0; } /* ================== Mod_FindName ================== */ qmodel_t *Mod_FindName (const char *name) { int i; qmodel_t *mod; if (!name[0]) Sys_Error ("Mod_FindName: NULL name"); //johnfitz -- was "Mod_ForName" // // search the currently loaded models // for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) if (!strcmp (mod->name, name) ) break; if (i == mod_numknown) { if (mod_numknown == MAX_MOD_KNOWN) Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); q_strlcpy (mod->name, name, MAX_QPATH); mod->needload = true; mod_numknown++; } return mod; } /* ================== Mod_TouchModel ================== */ void Mod_TouchModel (const char *name) { qmodel_t *mod; mod = Mod_FindName (name); if (!mod->needload) { if (mod->type == mod_alias) Cache_Check (&mod->cache); } } /* ================== Mod_LoadModel Loads a model into the cache ================== */ qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash) { byte *buf; byte stackbuf[1024]; // avoid dirtying the cache heap int mod_type; if (!mod->needload) { if (mod->type == mod_alias) { if (Cache_Check (&mod->cache)) return mod; } else return mod; // not cached at all } // // because the world is so huge, load it one piece at a time // if (!crash) { } // // load the file // buf = COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), & mod->path_id); if (!buf) { if (crash) Sys_Error ("Mod_LoadModel: %s not found", mod->name); //johnfitz -- was "Mod_NumForName" return NULL; } // // allocate a new model // COM_FileBase (mod->name, loadname, sizeof(loadname)); loadmodel = mod; // // fill it in // // call the apropriate loader mod->needload = false; mod_type = (buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24)); switch (mod_type) { case IDPOLYHEADER: Mod_LoadAliasModel (mod, buf); break; case IDSPRITEHEADER: Mod_LoadSpriteModel (mod, buf); break; default: Mod_LoadBrushModel (mod, buf); break; } return mod; } /* ================== Mod_ForName Loads in a model for the given name ================== */ qmodel_t *Mod_ForName (const char *name, qboolean crash) { qmodel_t *mod; mod = Mod_FindName (name); return Mod_LoadModel (mod, crash); } /* =============================================================================== BRUSHMODEL LOADING =============================================================================== */ byte *mod_base; /* ================= Mod_CheckFullbrights -- johnfitz ================= */ qboolean Mod_CheckFullbrights (byte *pixels, int count) { int i; for (i = 0; i < count; i++) if (*pixels++ > 223) return true; return false; } /* ================= Mod_LoadTextures ================= */ void Mod_LoadTextures (lump_t *l) { int i, j, pixels, num, maxanim, altmax; miptex_t *mt; texture_t *tx, *tx2; texture_t *anims[10]; texture_t *altanims[10]; dmiptexlump_t *m; //johnfitz -- more variables char texturename[64]; int nummiptex; src_offset_t offset; int mark, fwidth, fheight; char filename[MAX_OSPATH], filename2[MAX_OSPATH], mapname[MAX_OSPATH]; byte *data; extern byte *hunk_base; //johnfitz //johnfitz -- don't return early if no textures; still need to create dummy texture if (!l->filelen) { Con_Printf ("Mod_LoadTextures: no textures in bsp file\n"); nummiptex = 0; m = NULL; // avoid bogus compiler warning } else { m = (dmiptexlump_t *)(mod_base + l->fileofs); m->nummiptex = LittleLong (m->nummiptex); nummiptex = m->nummiptex; } //johnfitz loadmodel->numtextures = nummiptex + 2; //johnfitz -- need 2 dummy texture chains for missing textures loadmodel->textures = (texture_t **) Hunk_AllocName (loadmodel->numtextures * sizeof(*loadmodel->textures) , loadname); for (i=0 ; i<nummiptex ; i++) { m->dataofs[i] = LittleLong(m->dataofs[i]); if (m->dataofs[i] == -1) continue; mt = (miptex_t *)((byte *)m + m->dataofs[i]); mt->width = LittleLong (mt->width); mt->height = LittleLong (mt->height); for (j=0 ; j<MIPLEVELS ; j++) mt->offsets[j] = LittleLong (mt->offsets[j]); if ( (mt->width & 15) || (mt->height & 15) ) Sys_Error ("Texture %s is not 16 aligned", mt->name); pixels = mt->width*mt->height/64*85; tx = (texture_t *) Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); loadmodel->textures[i] = tx; memcpy (tx->name, mt->name, sizeof(tx->name)); tx->width = mt->width; tx->height = mt->height; for (j=0 ; j<MIPLEVELS ; j++) tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); // the pixels immediately follow the structures // ericw -- check for pixels extending past the end of the lump. // appears in the wild; e.g. jam2_tronyn.bsp (func_mapjam2), // kellbase1.bsp (quoth), and can lead to a segfault if we read past // the end of the .bsp file buffer if (((byte*)(mt+1) + pixels) > (mod_base + l->fileofs + l->filelen)) { Con_DPrintf("Texture %s extends past end of lump\n", mt->name); pixels = q_max(0, (mod_base + l->fileofs + l->filelen) - (byte*)(mt+1)); } memcpy ( tx+1, mt+1, pixels); tx->update_warp = false; //johnfitz tx->warpimage = NULL; //johnfitz tx->fullbright = NULL; //johnfitz //johnfitz -- lots of changes if (!isDedicated) //no texture uploading for dedicated server { if (!q_strncasecmp(tx->name,"sky",3)) //sky texture //also note -- was Q_strncmp, changed to match qbsp Sky_LoadTexture (tx); else if (tx->name[0] == '*') //warping texture { //external textures -- first look in "textures/mapname/" then look in "textures/" mark = Hunk_LowMark(); COM_StripExtension (loadmodel->name + 5, mapname, sizeof(mapname)); q_snprintf (filename, sizeof(filename), "textures/%s/#%s", mapname, tx->name+1); //this also replaces the '*' with a '#' data = Image_LoadImage (filename, &fwidth, &fheight); if (!data) { q_snprintf (filename, sizeof(filename), "textures/#%s", tx->name+1); data = Image_LoadImage (filename, &fwidth, &fheight); } //now load whatever we found if (data) //load external image { q_strlcpy (texturename, filename, sizeof(texturename)); tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, fwidth, fheight, SRC_RGBA, data, filename, 0, TEXPREF_NONE); } else //use the texture from the bsp file { q_snprintf (texturename, sizeof(texturename), "%s:%s", loadmodel->name, tx->name); offset = (src_offset_t)(mt+1) - (src_offset_t)mod_base; tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_NONE); } //now create the warpimage, using dummy data from the hunk to create the initial image Hunk_Alloc (gl_warpimagesize*gl_warpimagesize*4); //make sure hunk is big enough so we don't reach an illegal address Hunk_FreeToLowMark (mark); q_snprintf (texturename, sizeof(texturename), "%s_warp", texturename); tx->warpimage = TexMgr_LoadImage (loadmodel, texturename, gl_warpimagesize, gl_warpimagesize, SRC_RGBA, hunk_base, "", (src_offset_t)hunk_base, TEXPREF_NOPICMIP | TEXPREF_WARPIMAGE); tx->update_warp = true; } else //regular texture { // ericw -- fence textures int extraflags; extraflags = 0; if (tx->name[0] == '{') extraflags |= TEXPREF_ALPHA; // ericw //external textures -- first look in "textures/mapname/" then look in "textures/" mark = Hunk_LowMark (); COM_StripExtension (loadmodel->name + 5, mapname, sizeof(mapname)); q_snprintf (filename, sizeof(filename), "textures/%s/%s", mapname, tx->name); data = Image_LoadImage (filename, &fwidth, &fheight); if (!data) { q_snprintf (filename, sizeof(filename), "textures/%s", tx->name); data = Image_LoadImage (filename, &fwidth, &fheight); } //now load whatever we found if (data) //load external image { tx->gltexture = TexMgr_LoadImage (loadmodel, filename, fwidth, fheight, SRC_RGBA, data, filename, 0, TEXPREF_MIPMAP | extraflags ); //now try to load glow/luma image from the same place Hunk_FreeToLowMark (mark); q_snprintf (filename2, sizeof(filename2), "%s_glow", filename); data = Image_LoadImage (filename2, &fwidth, &fheight); if (!data) q_snprintf (filename2, sizeof(filename2), "%s_luma", filename); data = Image_LoadImage (filename2, &fwidth, &fheight); if (data) tx->fullbright = TexMgr_LoadImage (loadmodel, filename2, fwidth, fheight, SRC_RGBA, data, filename, 0, TEXPREF_MIPMAP | extraflags ); } else //use the texture from the bsp file { q_snprintf (texturename, sizeof(texturename), "%s:%s", loadmodel->name, tx->name); offset = (src_offset_t)(mt+1) - (src_offset_t)mod_base; if (Mod_CheckFullbrights ((byte *)(tx+1), pixels)) { tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP | TEXPREF_NOBRIGHT | extraflags); q_snprintf (texturename, sizeof(texturename), "%s:%s_glow", loadmodel->name, tx->name); tx->fullbright = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP | TEXPREF_FULLBRIGHT | extraflags); } else { tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP | extraflags); } } Hunk_FreeToLowMark (mark); } } //johnfitz } //johnfitz -- last 2 slots in array should be filled with dummy textures loadmodel->textures[loadmodel->numtextures-2] = r_notexture_mip; //for lightmapped surfs loadmodel->textures[loadmodel->numtextures-1] = r_notexture_mip2; //for SURF_DRAWTILED surfs // // sequence the animations // for (i=0 ; i<nummiptex ; i++) { tx = loadmodel->textures[i]; if (!tx || tx->name[0] != '+') continue; if (tx->anim_next) continue; // allready sequenced // find the number of frames in the animation memset (anims, 0, sizeof(anims)); memset (altanims, 0, sizeof(altanims)); maxanim = tx->name[1]; altmax = 0; if (maxanim >= 'a' && maxanim <= 'z') maxanim -= 'a' - 'A'; if (maxanim >= '0' && maxanim <= '9') { maxanim -= '0'; altmax = 0; anims[maxanim] = tx; maxanim++; } else if (maxanim >= 'A' && maxanim <= 'J') { altmax = maxanim - 'A'; maxanim = 0; altanims[altmax] = tx; altmax++; } else Sys_Error ("Bad animating texture %s", tx->name); for (j=i+1 ; j<nummiptex ; j++) { tx2 = loadmodel->textures[j]; if (!tx2 || tx2->name[0] != '+') continue; if (strcmp (tx2->name+2, tx->name+2)) continue; num = tx2->name[1]; if (num >= 'a' && num <= 'z') num -= 'a' - 'A'; if (num >= '0' && num <= '9') { num -= '0'; anims[num] = tx2; if (num+1 > maxanim) maxanim = num + 1; } else if (num >= 'A' && num <= 'J') { num = num - 'A'; altanims[num] = tx2; if (num+1 > altmax) altmax = num+1; } else Sys_Error ("Bad animating texture %s", tx->name); } #define ANIM_CYCLE 2 // link them all together for (j=0 ; j<maxanim ; j++) { tx2 = anims[j]; if (!tx2) Sys_Error ("Missing frame %i of %s",j, tx->name); tx2->anim_total = maxanim * ANIM_CYCLE; tx2->anim_min = j * ANIM_CYCLE; tx2->anim_max = (j+1) * ANIM_CYCLE; tx2->anim_next = anims[ (j+1)%maxanim ]; if (altmax) tx2->alternate_anims = altanims[0]; } for (j=0 ; j<altmax ; j++) { tx2 = altanims[j]; if (!tx2) Sys_Error ("Missing frame %i of %s",j, tx->name); tx2->anim_total = altmax * ANIM_CYCLE; tx2->anim_min = j * ANIM_CYCLE; tx2->anim_max = (j+1) * ANIM_CYCLE; tx2->anim_next = altanims[ (j+1)%altmax ]; if (maxanim) tx2->alternate_anims = anims[0]; } } } /* ================= Mod_LoadLighting -- johnfitz -- replaced with lit support code via lordhavoc ================= */ void Mod_LoadLighting (lump_t *l) { int i, mark; byte *in, *out, *data; byte d; char litfilename[MAX_OSPATH]; unsigned int path_id; loadmodel->lightdata = NULL; // LordHavoc: check for a .lit file q_strlcpy(litfilename, loadmodel->name, sizeof(litfilename)); COM_StripExtension(litfilename, litfilename, sizeof(litfilename)); q_strlcat(litfilename, ".lit", sizeof(litfilename)); mark = Hunk_LowMark(); data = (byte*) COM_LoadHunkFile (litfilename, &path_id); if (data) { // use lit file only from the same gamedir as the map // itself or from a searchpath with higher priority. if (path_id < loadmodel->path_id) { Hunk_FreeToLowMark(mark); Con_DPrintf("ignored %s from a gamedir with lower priority\n", litfilename); } else if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') { i = LittleLong(((int *)data)[1]); if (i == 1) { Con_DPrintf("%s loaded\n", litfilename); loadmodel->lightdata = data + 8; return; } else { Hunk_FreeToLowMark(mark); Con_Printf("Unknown .lit file version (%d)\n", i); } } else { Hunk_FreeToLowMark(mark); Con_Printf("Corrupt .lit file (old version?), ignoring\n"); } } // LordHavoc: no .lit found, expand the white lighting data to color if (!l->filelen) return; loadmodel->lightdata = (byte *) Hunk_AllocName ( l->filelen*3, litfilename); in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write out = loadmodel->lightdata; memcpy (in, mod_base + l->fileofs, l->filelen); for (i = 0;i < l->filelen;i++) { d = *in++; *out++ = d; *out++ = d; *out++ = d; } } /* ================= Mod_LoadVisibility ================= */ void Mod_LoadVisibility (lump_t *l) { if (!l->filelen) { loadmodel->visdata = NULL; return; } loadmodel->visdata = (byte *) Hunk_AllocName ( l->filelen, loadname); memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen); } /* ================= Mod_LoadEntities ================= */ void Mod_LoadEntities (lump_t *l) { char entfilename[MAX_QPATH]; char *ents; int mark; unsigned int path_id; if (! external_ents.value) goto _load_embedded; q_strlcpy(entfilename, loadmodel->name, sizeof(entfilename)); COM_StripExtension(entfilename, entfilename, sizeof(entfilename)); q_strlcat(entfilename, ".ent", sizeof(entfilename)); Con_DPrintf2("trying to load %s\n", entfilename); mark = Hunk_LowMark(); ents = (char *) COM_LoadHunkFile (entfilename, &path_id); if (ents) { // use ent file only from the same gamedir as the map // itself or from a searchpath with higher priority. if (path_id < loadmodel->path_id) { Hunk_FreeToLowMark(mark); Con_DPrintf("ignored %s from a gamedir with lower priority\n", entfilename); } else { loadmodel->entities = ents; Con_DPrintf("Loaded external entity file %s\n", entfilename); return; } } _load_embedded: if (!l->filelen) { loadmodel->entities = NULL; return; } loadmodel->entities = (char *) Hunk_AllocName ( l->filelen, loadname); memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen); } /* ================= Mod_LoadVertexes ================= */ void Mod_LoadVertexes (lump_t *l) { dvertex_t *in; mvertex_t *out; int i, count; in = (dvertex_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (mvertex_t *) Hunk_AllocName ( count*sizeof(*out), loadname); loadmodel->vertexes = out; loadmodel->numvertexes = count; for (i=0 ; i<count ; i++, in++, out++) { out->position[0] = LittleFloat (in->point[0]); out->position[1] = LittleFloat (in->point[1]); out->position[2] = LittleFloat (in->point[2]); } } /* ================= Mod_LoadEdges ================= */ void Mod_LoadEdges (lump_t *l, int bsp2) { medge_t *out; int i, count; if (bsp2) { dledge_t *in = (dledge_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (medge_t *) Hunk_AllocName ( (count + 1) * sizeof(*out), loadname); loadmodel->edges = out; loadmodel->numedges = count; for (i=0 ; i<count ; i++, in++, out++) { out->v[0] = LittleLong(in->v[0]); out->v[1] = LittleLong(in->v[1]); } } else { dsedge_t *in = (dsedge_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (medge_t *) Hunk_AllocName ( (count + 1) * sizeof(*out), loadname); loadmodel->edges = out; loadmodel->numedges = count; for (i=0 ; i<count ; i++, in++, out++) { out->v[0] = (unsigned short)LittleShort(in->v[0]); out->v[1] = (unsigned short)LittleShort(in->v[1]); } } } /* ================= Mod_LoadTexinfo ================= */ void Mod_LoadTexinfo (lump_t *l) { texinfo_t *in; mtexinfo_t *out; int i, j, count, miptex; float len1, len2; int missing = 0; //johnfitz in = (texinfo_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (mtexinfo_t *) Hunk_AllocName ( count*sizeof(*out), loadname); loadmodel->texinfo = out; loadmodel->numtexinfo = count; for (i=0 ; i<count ; i++, in++, out++) { for (j=0 ; j<4 ; j++) { out->vecs[0][j] = LittleFloat (in->vecs[0][j]); out->vecs[1][j] = LittleFloat (in->vecs[1][j]); } len1 = VectorLength (out->vecs[0]); len2 = VectorLength (out->vecs[1]); len1 = (len1 + len2)/2; if (len1 < 0.32) out->mipadjust = 4; else if (len1 < 0.49) out->mipadjust = 3; else if (len1 < 0.99) out->mipadjust = 2; else out->mipadjust = 1; #if 0 if (len1 + len2 < 0.001) out->mipadjust = 1; // don't crash else out->mipadjust = 1 / floor((len1+len2)/2 + 0.1); #endif miptex = LittleLong (in->miptex); out->flags = LittleLong (in->flags); //johnfitz -- rewrote this section if (miptex >= loadmodel->numtextures-1 || !loadmodel->textures[miptex]) { if (out->flags & TEX_SPECIAL) out->texture = loadmodel->textures[loadmodel->numtextures-1]; else out->texture = loadmodel->textures[loadmodel->numtextures-2]; out->flags |= TEX_MISSING; missing++; } else { out->texture = loadmodel->textures[miptex]; } //johnfitz } //johnfitz: report missing textures if (missing && loadmodel->numtextures > 1) Con_Printf ("Mod_LoadTexinfo: %d texture(s) missing from BSP file\n", missing); //johnfitz } /* ================ CalcSurfaceExtents Fills in s->texturemins[] and s->extents[] ================ */ void CalcSurfaceExtents (msurface_t *s) { float mins[2], maxs[2], val; int i,j, e; mvertex_t *v; mtexinfo_t *tex; int bmins[2], bmaxs[2]; mins[0] = mins[1] = 999999; maxs[0] = maxs[1] = -99999; tex = s->texinfo; for (i=0 ; i<s->numedges ; i++) { e = loadmodel->surfedges[s->firstedge+i]; if (e >= 0) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; for (j=0 ; j<2 ; j++) { /* The following calculation is sensitive to floating-point * precision. It needs to produce the same result that the * light compiler does, because R_BuildLightMap uses surf-> * extents to know the width/height of a surface's lightmap, * and incorrect rounding here manifests itself as patches * of "corrupted" looking lightmaps. * Most light compilers are win32 executables, so they use * x87 floating point. This means the multiplies and adds * are done at 80-bit precision, and the result is rounded * down to 32-bits and stored in val. * Adding the casts to double seems to be good enough to fix * lighting glitches when Quakespasm is compiled as x86_64 * and using SSE2 floating-point. A potential trouble spot * is the hallway at the beginning of mfxsp17. -- ericw */ val = ((double)v->position[0] * (double)tex->vecs[j][0]) + ((double)v->position[1] * (double)tex->vecs[j][1]) + ((double)v->position[2] * (double)tex->vecs[j][2]) + (double)tex->vecs[j][3]; if (val < mins[j]) mins[j] = val; if (val > maxs[j]) maxs[j] = val; } } for (i=0 ; i<2 ; i++) { bmins[i] = floor(mins[i]/16); bmaxs[i] = ceil(maxs[i]/16); s->texturemins[i] = bmins[i] * 16; s->extents[i] = (bmaxs[i] - bmins[i]) * 16; if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 2000) //johnfitz -- was 512 in glquake, 256 in winquake Sys_Error ("Bad surface extents"); } } /* ================ Mod_PolyForUnlitSurface -- johnfitz -- creates polys for unlightmapped surfaces (sky and water) TODO: merge this into BuildSurfaceDisplayList? ================ */ void Mod_PolyForUnlitSurface (msurface_t *fa) { vec3_t verts[64]; int numverts, i, lindex; float *vec; glpoly_t *poly; float texscale; if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) texscale = (1.0/128.0); //warp animation repeats every 128 else texscale = (1.0/32.0); //to match r_notexture_mip // convert edges back to a normal polygon numverts = 0; for (i=0 ; i<fa->numedges ; i++) { lindex = loadmodel->surfedges[fa->firstedge + i]; if (lindex > 0) vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; else vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; VectorCopy (vec, verts[numverts]); numverts++; } //create the poly poly = (glpoly_t *) Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float)); poly->next = NULL; fa->polys = poly; poly->numverts = numverts; for (i=0, vec=(float *)verts; i<numverts; i++, vec+= 3) { VectorCopy (vec, poly->verts[i]); poly->verts[i][3] = DotProduct(vec, fa->texinfo->vecs[0]) * texscale; poly->verts[i][4] = DotProduct(vec, fa->texinfo->vecs[1]) * texscale; } } /* ================= Mod_CalcSurfaceBounds -- johnfitz -- calculate bounding box for per-surface frustum culling ================= */ void Mod_CalcSurfaceBounds (msurface_t *s) { int i, e; mvertex_t *v; s->mins[0] = s->mins[1] = s->mins[2] = 9999; s->maxs[0] = s->maxs[1] = s->maxs[2] = -9999; for (i=0 ; i<s->numedges ; i++) { e = loadmodel->surfedges[s->firstedge+i]; if (e >= 0) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; if (s->mins[0] > v->position[0]) s->mins[0] = v->position[0]; if (s->mins[1] > v->position[1]) s->mins[1] = v->position[1]; if (s->mins[2] > v->position[2]) s->mins[2] = v->position[2]; if (s->maxs[0] < v->position[0]) s->maxs[0] = v->position[0]; if (s->maxs[1] < v->position[1]) s->maxs[1] = v->position[1]; if (s->maxs[2] < v->position[2]) s->maxs[2] = v->position[2]; } } /* ================= Mod_LoadFaces ================= */ void Mod_LoadFaces (lump_t *l, qboolean bsp2) { dsface_t *ins; dlface_t *inl; msurface_t *out; int i, count, surfnum, lofs; int planenum, side, texinfon; if (bsp2) { ins = NULL; inl = (dlface_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*inl)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*inl); } else { ins = (dsface_t *)(mod_base + l->fileofs); inl = NULL; if (l->filelen % sizeof(*ins)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*ins); } out = (msurface_t *)Hunk_AllocName ( count*sizeof(*out), loadname); //johnfitz -- warn mappers about exceeding old limits if (count > 32767 && !bsp2) Con_DWarning ("%i faces exceeds standard limit of 32767.\n", count); //johnfitz loadmodel->surfaces = out; loadmodel->numsurfaces = count; for (surfnum=0 ; surfnum<count ; surfnum++, out++) { if (bsp2) { out->firstedge = LittleLong(inl->firstedge); out->numedges = LittleLong(inl->numedges); planenum = LittleLong(inl->planenum); side = LittleLong(inl->side); texinfon = LittleLong (inl->texinfo); for (i=0 ; i<MAXLIGHTMAPS ; i++) out->styles[i] = inl->styles[i]; lofs = LittleLong(inl->lightofs); inl++; } else { out->firstedge = LittleLong(ins->firstedge); out->numedges = LittleShort(ins->numedges); planenum = LittleShort(ins->planenum); side = LittleShort(ins->side); texinfon = LittleShort (ins->texinfo); for (i=0 ; i<MAXLIGHTMAPS ; i++) out->styles[i] = ins->styles[i]; lofs = LittleLong(ins->lightofs); ins++; } out->flags = 0; if (side) out->flags |= SURF_PLANEBACK; out->plane = loadmodel->planes + planenum; out->texinfo = loadmodel->texinfo + texinfon; CalcSurfaceExtents (out); Mod_CalcSurfaceBounds (out); //johnfitz -- for per-surface frustum culling // lighting info if (lofs == -1) out->samples = NULL; else out->samples = loadmodel->lightdata + (lofs * 3); //johnfitz -- lit support via lordhavoc (was "+ i") //johnfitz -- this section rewritten if (!q_strncasecmp(out->texinfo->texture->name,"sky",3)) // sky surface //also note -- was Q_strncmp, changed to match qbsp { out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); Mod_PolyForUnlitSurface (out); //no more subdivision } else if (out->texinfo->texture->name[0] == '*') // warp surface { out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); // detect special liquid types if (!strncmp (out->texinfo->texture->name, "*lava", 5)) out->flags |= SURF_DRAWLAVA; else if (!strncmp (out->texinfo->texture->name, "*slime", 6)) out->flags |= SURF_DRAWSLIME; else if (!strncmp (out->texinfo->texture->name, "*tele", 5)) out->flags |= SURF_DRAWTELE; else out->flags |= SURF_DRAWWATER; Mod_PolyForUnlitSurface (out); GL_SubdivideSurface (out); } else if (out->texinfo->texture->name[0] == '{') // ericw -- fence textures { out->flags |= SURF_DRAWFENCE; } else if (out->texinfo->flags & TEX_MISSING) // texture is missing from bsp { if (out->samples) //lightmapped { out->flags |= SURF_NOTEXTURE; } else // not lightmapped { out->flags |= (SURF_NOTEXTURE | SURF_DRAWTILED); Mod_PolyForUnlitSurface (out); } } //johnfitz } } /* ================= Mod_SetParent ================= */ void Mod_SetParent (mnode_t *node, mnode_t *parent) { node->parent = parent; if (node->contents < 0) return; Mod_SetParent (node->children[0], node); Mod_SetParent (node->children[1], node); } /* ================= Mod_LoadNodes ================= */ void Mod_LoadNodes_S (lump_t *l) { int i, j, count, p; dsnode_t *in; mnode_t *out; in = (dsnode_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (mnode_t *) Hunk_AllocName ( count*sizeof(*out), loadname); //johnfitz -- warn mappers about exceeding old limits if (count > 32767) Con_DWarning ("%i nodes exceeds standard limit of 32767.\n", count); //johnfitz loadmodel->nodes = out; loadmodel->numnodes = count; for (i=0 ; i<count ; i++, in++, out++) { for (j=0 ; j<3 ; j++) { out->minmaxs[j] = LittleShort (in->mins[j]); out->minmaxs[3+j] = LittleShort (in->maxs[j]); } p = LittleLong(in->planenum); out->plane = loadmodel->planes + p; out->firstsurface = (unsigned short)LittleShort (in->firstface); //johnfitz -- explicit cast as unsigned short out->numsurfaces = (unsigned short)LittleShort (in->numfaces); //johnfitz -- explicit cast as unsigned short for (j=0 ; j<2 ; j++) { //johnfitz -- hack to handle nodes > 32k, adapted from darkplaces p = (unsigned short)LittleShort(in->children[j]); if (p < count) out->children[j] = loadmodel->nodes + p; else { p = 65535 - p; //note this uses 65535 intentionally, -1 is leaf 0 if (p < loadmodel->numleafs) out->children[j] = (mnode_t *)(loadmodel->leafs + p); else { Con_Printf("Mod_LoadNodes: invalid leaf index %i (file has only %i leafs)\n", p, loadmodel->numleafs); out->children[j] = (mnode_t *)(loadmodel->leafs); //map it to the solid leaf } } //johnfitz } } } void Mod_LoadNodes_L1 (lump_t *l) { int i, j, count, p; dl1node_t *in; mnode_t *out; in = (dl1node_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("Mod_LoadNodes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (mnode_t *)Hunk_AllocName ( count*sizeof(*out), loadname); loadmodel->nodes = out; loadmodel->numnodes = count; for (i=0 ; i<count ; i++, in++, out++) { for (j=0 ; j<3 ; j++) { out->minmaxs[j] = LittleShort (in->mins[j]); out->minmaxs[3+j] = LittleShort (in->maxs[j]); } p = LittleLong(in->planenum); out->plane = loadmodel->planes + p; out->firstsurface = LittleLong (in->firstface); //johnfitz -- explicit cast as unsigned short out->numsurfaces = LittleLong (in->numfaces); //johnfitz -- explicit cast as unsigned short for (j=0 ; j<2 ; j++) { //johnfitz -- hack to handle nodes > 32k, adapted from darkplaces p = LittleLong(in->children[j]); if (p >= 0 && p < count) out->children[j] = loadmodel->nodes + p; else { p = 0xffffffff - p; //note this uses 65535 intentionally, -1 is leaf 0 if (p >= 0 && p < loadmodel->numleafs) out->children[j] = (mnode_t *)(loadmodel->leafs + p); else { Con_Printf("Mod_LoadNodes: invalid leaf index %i (file has only %i leafs)\n", p, loadmodel->numleafs); out->children[j] = (mnode_t *)(loadmodel->leafs); //map it to the solid leaf } } //johnfitz } } } void Mod_LoadNodes_L2 (lump_t *l) { int i, j, count, p; dl2node_t *in; mnode_t *out; in = (dl2node_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("Mod_LoadNodes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (mnode_t *)Hunk_AllocName ( count*sizeof(*out), loadname); loadmodel->nodes = out; loadmodel->numnodes = count; for (i=0 ; i<count ; i++, in++, out++) { for (j=0 ; j<3 ; j++) { out->minmaxs[j] = LittleFloat (in->mins[j]); out->minmaxs[3+j] = LittleFloat (in->maxs[j]); } p = LittleLong(in->planenum); out->plane = loadmodel->planes + p; out->firstsurface = LittleLong (in->firstface); //johnfitz -- explicit cast as unsigned short out->numsurfaces = LittleLong (in->numfaces); //johnfitz -- explicit cast as unsigned short for (j=0 ; j<2 ; j++) { //johnfitz -- hack to handle nodes > 32k, adapted from darkplaces p = LittleLong(in->children[j]); if (p > 0 && p < count) out->children[j] = loadmodel->nodes + p; else { p = 0xffffffff - p; //note this uses 65535 intentionally, -1 is leaf 0 if (p >= 0 && p < loadmodel->numleafs) out->children[j] = (mnode_t *)(loadmodel->leafs + p); else { Con_Printf("Mod_LoadNodes: invalid leaf index %i (file has only %i leafs)\n", p, loadmodel->numleafs); out->children[j] = (mnode_t *)(loadmodel->leafs); //map it to the solid leaf } } //johnfitz } } } void Mod_LoadNodes (lump_t *l, int bsp2) { if (bsp2 == 2) Mod_LoadNodes_L2(l); else if (bsp2) Mod_LoadNodes_L1(l); else Mod_LoadNodes_S(l); Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs } void Mod_ProcessLeafs_S (dsleaf_t *in, int filelen) { mleaf_t *out; int i, j, count, p; if (filelen % sizeof(*in)) Sys_Error ("Mod_ProcessLeafs: funny lump size in %s", loadmodel->name); count = filelen / sizeof(*in); out = (mleaf_t *) Hunk_AllocName ( count*sizeof(*out), loadname); //johnfitz if (count > 32767) Host_Error ("Mod_LoadLeafs: %i leafs exceeds limit of 32767.\n", count); //johnfitz loadmodel->leafs = out; loadmodel->numleafs = count; for (i=0 ; i<count ; i++, in++, out++) { for (j=0 ; j<3 ; j++) { out->minmaxs[j] = LittleShort (in->mins[j]); out->minmaxs[3+j] = LittleShort (in->maxs[j]); } p = LittleLong(in->contents); out->contents = p; out->firstmarksurface = loadmodel->marksurfaces + (unsigned short)LittleShort(in->firstmarksurface); //johnfitz -- unsigned short out->nummarksurfaces = (unsigned short)LittleShort(in->nummarksurfaces); //johnfitz -- unsigned short p = LittleLong(in->visofs); if (p == -1) out->compressed_vis = NULL; else out->compressed_vis = loadmodel->visdata + p; out->efrags = NULL; for (j=0 ; j<4 ; j++) out->ambient_sound_level[j] = in->ambient_level[j]; //johnfitz -- removed code to mark surfaces as SURF_UNDERWATER } } void Mod_ProcessLeafs_L1 (dl1leaf_t *in, int filelen) { mleaf_t *out; int i, j, count, p; if (filelen % sizeof(*in)) Sys_Error ("Mod_ProcessLeafs: funny lump size in %s", loadmodel->name); count = filelen / sizeof(*in); out = (mleaf_t *) Hunk_AllocName (count * sizeof(*out), loadname); if (count > MAX_MAP_LEAFS) Host_Error ("Mod_LoadLeafs: %i leafs exceeds limit of %i.\n", count, MAX_MAP_LEAFS); loadmodel->leafs = out; loadmodel->numleafs = count; for (i=0 ; i<count ; i++, in++, out++) { for (j=0 ; j<3 ; j++) { out->minmaxs[j] = LittleShort (in->mins[j]); out->minmaxs[3+j] = LittleShort (in->maxs[j]); } p = LittleLong(in->contents); out->contents = p; out->firstmarksurface = loadmodel->marksurfaces + LittleLong(in->firstmarksurface); //johnfitz -- unsigned short out->nummarksurfaces = LittleLong(in->nummarksurfaces); //johnfitz -- unsigned short p = LittleLong(in->visofs); if (p == -1) out->compressed_vis = NULL; else out->compressed_vis = loadmodel->visdata + p; out->efrags = NULL; for (j=0 ; j<4 ; j++) out->ambient_sound_level[j] = in->ambient_level[j]; //johnfitz -- removed code to mark surfaces as SURF_UNDERWATER } } void Mod_ProcessLeafs_L2 (dl2leaf_t *in, int filelen) { mleaf_t *out; int i, j, count, p; if (filelen % sizeof(*in)) Sys_Error ("Mod_ProcessLeafs: funny lump size in %s", loadmodel->name); count = filelen / sizeof(*in); out = (mleaf_t *) Hunk_AllocName (count * sizeof(*out), loadname); if (count > MAX_MAP_LEAFS) Host_Error ("Mod_LoadLeafs: %i leafs exceeds limit of %i.\n", count, MAX_MAP_LEAFS); loadmodel->leafs = out; loadmodel->numleafs = count; for (i=0 ; i<count ; i++, in++, out++) { for (j=0 ; j<3 ; j++) { out->minmaxs[j] = LittleFloat (in->mins[j]); out->minmaxs[3+j] = LittleFloat (in->maxs[j]); } p = LittleLong(in->contents); out->contents = p; out->firstmarksurface = loadmodel->marksurfaces + LittleLong(in->firstmarksurface); //johnfitz -- unsigned short out->nummarksurfaces = LittleLong(in->nummarksurfaces); //johnfitz -- unsigned short p = LittleLong(in->visofs); if (p == -1) out->compressed_vis = NULL; else out->compressed_vis = loadmodel->visdata + p; out->efrags = NULL; for (j=0 ; j<4 ; j++) out->ambient_sound_level[j] = in->ambient_level[j]; //johnfitz -- removed code to mark surfaces as SURF_UNDERWATER } } /* ================= Mod_LoadLeafs ================= */ void Mod_LoadLeafs (lump_t *l, int bsp2) { void *in = (void *)(mod_base + l->fileofs); if (bsp2 == 2) Mod_ProcessLeafs_L2 ((dl2leaf_t *)in, l->filelen); else if (bsp2) Mod_ProcessLeafs_L1 ((dl1leaf_t *)in, l->filelen); else Mod_ProcessLeafs_S ((dsleaf_t *) in, l->filelen); } /* ================= Mod_LoadClipnodes ================= */ void Mod_LoadClipnodes (lump_t *l, qboolean bsp2) { dsclipnode_t *ins; dlclipnode_t *inl; mclipnode_t *out; //johnfitz -- was dclipnode_t int i, count; hull_t *hull; if (bsp2) { ins = NULL; inl = (dlclipnode_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*inl)) Sys_Error ("Mod_LoadClipnodes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*inl); } else { ins = (dsclipnode_t *)(mod_base + l->fileofs); inl = NULL; if (l->filelen % sizeof(*ins)) Sys_Error ("Mod_LoadClipnodes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*ins); } out = (mclipnode_t *) Hunk_AllocName ( count*sizeof(*out), loadname); //johnfitz -- warn about exceeding old limits if (count > 32767 && !bsp2) Con_DWarning ("%i clipnodes exceeds standard limit of 32767.\n", count); //johnfitz loadmodel->clipnodes = out; loadmodel->numclipnodes = count; hull = &loadmodel->hulls[1]; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; hull->clip_mins[0] = -16; hull->clip_mins[1] = -16; hull->clip_mins[2] = -24; hull->clip_maxs[0] = 16; hull->clip_maxs[1] = 16; hull->clip_maxs[2] = 32; hull = &loadmodel->hulls[2]; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; hull->clip_mins[0] = -32; hull->clip_mins[1] = -32; hull->clip_mins[2] = -24; hull->clip_maxs[0] = 32; hull->clip_maxs[1] = 32; hull->clip_maxs[2] = 64; if (bsp2) { for (i=0 ; i<count ; i++, out++, inl++) { out->planenum = LittleLong(inl->planenum); //johnfitz -- bounds check if (out->planenum < 0 || out->planenum >= loadmodel->numplanes) Host_Error ("Mod_LoadClipnodes: planenum out of bounds"); //johnfitz out->children[0] = LittleLong(inl->children[0]); out->children[1] = LittleLong(inl->children[1]); //Spike: FIXME: bounds check } } else { for (i=0 ; i<count ; i++, out++, ins++) { out->planenum = LittleLong(ins->planenum); //johnfitz -- bounds check if (out->planenum < 0 || out->planenum >= loadmodel->numplanes) Host_Error ("Mod_LoadClipnodes: planenum out of bounds"); //johnfitz //johnfitz -- support clipnodes > 32k out->children[0] = (unsigned short)LittleShort(ins->children[0]); out->children[1] = (unsigned short)LittleShort(ins->children[1]); if (out->children[0] >= count) out->children[0] -= 65536; if (out->children[1] >= count) out->children[1] -= 65536; //johnfitz } } } /* ================= Mod_MakeHull0 Duplicate the drawing hull structure as a clipping hull ================= */ void Mod_MakeHull0 (void) { mnode_t *in, *child; mclipnode_t *out; //johnfitz -- was dclipnode_t int i, j, count; hull_t *hull; hull = &loadmodel->hulls[0]; in = loadmodel->nodes; count = loadmodel->numnodes; out = (mclipnode_t *) Hunk_AllocName ( count*sizeof(*out), loadname); hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; for (i=0 ; i<count ; i++, out++, in++) { out->planenum = in->plane - loadmodel->planes; for (j=0 ; j<2 ; j++) { child = in->children[j]; if (child->contents < 0) out->children[j] = child->contents; else out->children[j] = child - loadmodel->nodes; } } } /* ================= Mod_LoadMarksurfaces ================= */ void Mod_LoadMarksurfaces (lump_t *l, int bsp2) { int i, j, count; msurface_t **out; if (bsp2) { unsigned int *in = (unsigned int *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Host_Error ("Mod_LoadMarksurfaces: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (msurface_t **)Hunk_AllocName ( count*sizeof(*out), loadname); loadmodel->marksurfaces = out; loadmodel->nummarksurfaces = count; for (i=0 ; i<count ; i++) { j = LittleLong(in[i]); if (j >= loadmodel->numsurfaces) Host_Error ("Mod_LoadMarksurfaces: bad surface number"); out[i] = loadmodel->surfaces + j; } } else { short *in = (short *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Host_Error ("Mod_LoadMarksurfaces: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (msurface_t **)Hunk_AllocName ( count*sizeof(*out), loadname); loadmodel->marksurfaces = out; loadmodel->nummarksurfaces = count; //johnfitz -- warn mappers about exceeding old limits if (count > 32767) Con_DWarning ("%i marksurfaces exceeds standard limit of 32767.\n", count); //johnfitz for (i=0 ; i<count ; i++) { j = (unsigned short)LittleShort(in[i]); //johnfitz -- explicit cast as unsigned short if (j >= loadmodel->numsurfaces) Sys_Error ("Mod_LoadMarksurfaces: bad surface number"); out[i] = loadmodel->surfaces + j; } } } /* ================= Mod_LoadSurfedges ================= */ void Mod_LoadSurfedges (lump_t *l) { int i, count; int *in, *out; in = (int *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (int *) Hunk_AllocName ( count*sizeof(*out), loadname); loadmodel->surfedges = out; loadmodel->numsurfedges = count; for (i=0 ; i<count ; i++) out[i] = LittleLong (in[i]); } /* ================= Mod_LoadPlanes ================= */ void Mod_LoadPlanes (lump_t *l) { int i, j; mplane_t *out; dplane_t *in; int count; int bits; in = (dplane_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (mplane_t *) Hunk_AllocName ( count*2*sizeof(*out), loadname); loadmodel->planes = out; loadmodel->numplanes = count; for (i=0 ; i<count ; i++, in++, out++) { bits = 0; for (j=0 ; j<3 ; j++) { out->normal[j] = LittleFloat (in->normal[j]); if (out->normal[j] < 0) bits |= 1<<j; } out->dist = LittleFloat (in->dist); out->type = LittleLong (in->type); out->signbits = bits; } } /* ================= RadiusFromBounds ================= */ float RadiusFromBounds (vec3_t mins, vec3_t maxs) { int i; vec3_t corner; for (i=0 ; i<3 ; i++) { corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); } return VectorLength (corner); } /* ================= Mod_LoadSubmodels ================= */ void Mod_LoadSubmodels (lump_t *l) { dmodel_t *in; dmodel_t *out; int i, j, count; in = (dmodel_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = (dmodel_t *) Hunk_AllocName ( count*sizeof(*out), loadname); loadmodel->submodels = out; loadmodel->numsubmodels = count; for (i=0 ; i<count ; i++, in++, out++) { for (j=0 ; j<3 ; j++) { // spread the mins / maxs by a pixel out->mins[j] = LittleFloat (in->mins[j]) - 1; out->maxs[j] = LittleFloat (in->maxs[j]) + 1; out->origin[j] = LittleFloat (in->origin[j]); } for (j=0 ; j<MAX_MAP_HULLS ; j++) out->headnode[j] = LittleLong (in->headnode[j]); out->visleafs = LittleLong (in->visleafs); out->firstface = LittleLong (in->firstface); out->numfaces = LittleLong (in->numfaces); } // johnfitz -- check world visleafs -- adapted from bjp out = loadmodel->submodels; if (out->visleafs > MAX_MAP_LEAFS) Sys_Error ("Mod_LoadSubmodels: too many visleafs (%d, max = %d) in %s", out->visleafs, MAX_MAP_LEAFS, loadmodel->name); if (out->visleafs > 8192) Con_DWarning ("%i visleafs exceeds standard limit of 8192.\n", out->visleafs); //johnfitz } /* ================= Mod_BoundsFromClipNode -- johnfitz update the model's clipmins and clipmaxs based on each node's plane. This works because of the way brushes are expanded in hull generation. Each brush will include all six axial planes, which bound that brush. Therefore, the bounding box of the hull can be constructed entirely from axial planes found in the clipnodes for that hull. ================= */ void Mod_BoundsFromClipNode (qmodel_t *mod, int hull, int nodenum) { mplane_t *plane; mclipnode_t *node; if (nodenum < 0) return; //hit a leafnode node = &mod->clipnodes[nodenum]; plane = mod->hulls[hull].planes + node->planenum; switch (plane->type) { case PLANE_X: if (plane->signbits == 1) mod->clipmins[0] = q_min(mod->clipmins[0], -plane->dist - mod->hulls[hull].clip_mins[0]); else mod->clipmaxs[0] = q_max(mod->clipmaxs[0], plane->dist - mod->hulls[hull].clip_maxs[0]); break; case PLANE_Y: if (plane->signbits == 2) mod->clipmins[1] = q_min(mod->clipmins[1], -plane->dist - mod->hulls[hull].clip_mins[1]); else mod->clipmaxs[1] = q_max(mod->clipmaxs[1], plane->dist - mod->hulls[hull].clip_maxs[1]); break; case PLANE_Z: if (plane->signbits == 4) mod->clipmins[2] = q_min(mod->clipmins[2], -plane->dist - mod->hulls[hull].clip_mins[2]); else mod->clipmaxs[2] = q_max(mod->clipmaxs[2], plane->dist - mod->hulls[hull].clip_maxs[2]); break; default: //skip nonaxial planes; don't need them break; } Mod_BoundsFromClipNode (mod, hull, node->children[0]); Mod_BoundsFromClipNode (mod, hull, node->children[1]); } /* ================= Mod_LoadBrushModel ================= */ void Mod_LoadBrushModel (qmodel_t *mod, void *buffer) { int i, j; int bsp2; dheader_t *header; dmodel_t *bm; float radius; //johnfitz loadmodel->type = mod_brush; header = (dheader_t *)buffer; mod->bspversion = LittleLong (header->version); switch(mod->bspversion) { case BSPVERSION: bsp2 = false; break; case BSP2VERSION_2PSB: bsp2 = 1; //first iteration break; case BSP2VERSION_BSP2: bsp2 = 2; //sanitised revision break; default: Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, mod->bspversion, BSPVERSION); break; } // swap all the lumps mod_base = (byte *)header; for (i = 0; i < (int) sizeof(dheader_t) / 4; i++) ((int *)header)[i] = LittleLong ( ((int *)header)[i]); // load into heap Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]); Mod_LoadEdges (&header->lumps[LUMP_EDGES], bsp2); Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]); Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); Mod_LoadFaces (&header->lumps[LUMP_FACES], bsp2); Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES], bsp2); Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); Mod_LoadLeafs (&header->lumps[LUMP_LEAFS], bsp2); Mod_LoadNodes (&header->lumps[LUMP_NODES], bsp2); Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES], bsp2); Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]); Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); Mod_MakeHull0 (); mod->numframes = 2; // regular and alternate animation // // set up the submodels (FIXME: this is confusing) // // johnfitz -- okay, so that i stop getting confused every time i look at this loop, here's how it works: // we're looping through the submodels starting at 0. Submodel 0 is the main model, so we don't have to // worry about clobbering data the first time through, since it's the same data. At the end of the loop, // we create a new copy of the data to use the next time through. for (i=0 ; i<mod->numsubmodels ; i++) { bm = &mod->submodels[i]; mod->hulls[0].firstclipnode = bm->headnode[0]; for (j=1 ; j<MAX_MAP_HULLS ; j++) { mod->hulls[j].firstclipnode = bm->headnode[j]; mod->hulls[j].lastclipnode = mod->numclipnodes-1; } mod->firstmodelsurface = bm->firstface; mod->nummodelsurfaces = bm->numfaces; VectorCopy (bm->maxs, mod->maxs); VectorCopy (bm->mins, mod->mins); //johnfitz -- calculate rotate bounds and yaw bounds radius = RadiusFromBounds (mod->mins, mod->maxs); mod->rmaxs[0] = mod->rmaxs[1] = mod->rmaxs[2] = mod->ymaxs[0] = mod->ymaxs[1] = mod->ymaxs[2] = radius; mod->rmins[0] = mod->rmins[1] = mod->rmins[2] = mod->ymins[0] = mod->ymins[1] = mod->ymins[2] = -radius; //johnfitz //johnfitz -- correct physics cullboxes so that outlying clip brushes on doors and stuff are handled right if (i > 0 || strcmp(mod->name, sv.modelname) != 0) //skip submodel 0 of sv.worldmodel, which is the actual world { // start with the hull0 bounds VectorCopy (mod->maxs, mod->clipmaxs); VectorCopy (mod->mins, mod->clipmins); // process hull1 (we don't need to process hull2 becuase there's // no such thing as a brush that appears in hull2 but not hull1) //Mod_BoundsFromClipNode (mod, 1, mod->hulls[1].firstclipnode); // (disabled for now becuase it fucks up on rotating models) } //johnfitz mod->numleafs = bm->visleafs; if (i < mod->numsubmodels-1) { // duplicate the basic information char name[10]; sprintf (name, "*%i", i+1); loadmodel = Mod_FindName (name); *loadmodel = *mod; strcpy (loadmodel->name, name); mod = loadmodel; } } } /* ============================================================================== ALIAS MODELS ============================================================================== */ aliashdr_t *pheader; stvert_t stverts[MAXALIASVERTS]; mtriangle_t triangles[MAXALIASTRIS]; // a pose is a single set of vertexes. a frame may be // an animating sequence of poses trivertx_t *poseverts[MAXALIASFRAMES]; int posenum; byte **player_8bit_texels_tbl; byte *player_8bit_texels; /* ================= Mod_LoadAliasFrame ================= */ void * Mod_LoadAliasFrame (void * pin, maliasframedesc_t *frame) { trivertx_t *pinframe; int i; daliasframe_t *pdaliasframe; pdaliasframe = (daliasframe_t *)pin; strcpy (frame->name, pdaliasframe->name); frame->firstpose = posenum; frame->numposes = 1; for (i=0 ; i<3 ; i++) { // these are byte values, so we don't have to worry about // endianness frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i]; frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i]; } pinframe = (trivertx_t *)(pdaliasframe + 1); poseverts[posenum] = pinframe; posenum++; pinframe += pheader->numverts; return (void *)pinframe; } /* ================= Mod_LoadAliasGroup ================= */ void *Mod_LoadAliasGroup (void * pin, maliasframedesc_t *frame) { daliasgroup_t *pingroup; int i, numframes; daliasinterval_t *pin_intervals; void *ptemp; pingroup = (daliasgroup_t *)pin; numframes = LittleLong (pingroup->numframes); frame->firstpose = posenum; frame->numposes = numframes; for (i=0 ; i<3 ; i++) { // these are byte values, so we don't have to worry about endianness frame->bboxmin.v[i] = pingroup->bboxmin.v[i]; frame->bboxmax.v[i] = pingroup->bboxmax.v[i]; } pin_intervals = (daliasinterval_t *)(pingroup + 1); frame->interval = LittleFloat (pin_intervals->interval); pin_intervals += numframes; ptemp = (void *)pin_intervals; for (i=0 ; i<numframes ; i++) { poseverts[posenum] = (trivertx_t *)((daliasframe_t *)ptemp + 1); posenum++; ptemp = (trivertx_t *)((daliasframe_t *)ptemp + 1) + pheader->numverts; } return ptemp; } //========================================================= /* ================= Mod_FloodFillSkin Fill background pixels so mipmapping doesn't have haloes - Ed ================= */ typedef struct { short x, y; } floodfill_t; // must be a power of 2 #define FLOODFILL_FIFO_SIZE 0x1000 #define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1) #define FLOODFILL_STEP( off, dx, dy ) \ do { \ if (pos[off] == fillcolor) \ { \ pos[off] = 255; \ fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ } \ else if (pos[off] != 255) fdc = pos[off]; \ } while (0) void Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight ) { byte fillcolor = *skin; // assume this is the pixel to fill floodfill_t fifo[FLOODFILL_FIFO_SIZE]; int inpt = 0, outpt = 0; int filledcolor = -1; int i; if (filledcolor == -1) { filledcolor = 0; // attempt to find opaque black for (i = 0; i < 256; ++i) if (d_8to24table[i] == (255 << 0)) // alpha 1.0 { filledcolor = i; break; } } // can't fill to filled color or to transparent color (used as visited marker) if ((fillcolor == filledcolor) || (fillcolor == 255)) { //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor ); return; } fifo[inpt].x = 0, fifo[inpt].y = 0; inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; while (outpt != inpt) { int x = fifo[outpt].x, y = fifo[outpt].y; int fdc = filledcolor; byte *pos = &skin[x + skinwidth * y]; outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; if (x > 0) FLOODFILL_STEP( -1, -1, 0 ); if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 ); if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 ); if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 ); skin[x + skinwidth * y] = fdc; } } /* =============== Mod_LoadAllSkins =============== */ void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype) { int i, j, k, size, groupskins; char name[MAX_QPATH]; byte *skin, *texels; daliasskingroup_t *pinskingroup; daliasskininterval_t *pinskinintervals; char fbr_mask_name[MAX_QPATH]; //johnfitz -- added for fullbright support src_offset_t offset; //johnfitz skin = (byte *)(pskintype + 1); if (numskins < 1 || numskins > MAX_SKINS) Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); size = pheader->skinwidth * pheader->skinheight; for (i=0 ; i<numskins ; i++) { if (pskintype->type == ALIAS_SKIN_SINGLE) { Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight ); // save 8 bit texels for the player model to remap texels = (byte *) Hunk_AllocName(size, loadname); pheader->texels[i] = texels - (byte *)pheader; memcpy (texels, (byte *)(pskintype + 1), size); //johnfitz -- rewritten q_snprintf (name, sizeof(name), "%s:frame%i", loadmodel->name, i); offset = (src_offset_t)(pskintype+1) - (src_offset_t)mod_base; if (Mod_CheckFullbrights ((byte *)(pskintype+1), size)) { pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_NOBRIGHT); q_snprintf (fbr_mask_name, sizeof(fbr_mask_name), "%s:frame%i_glow", loadmodel->name, i); pheader->fbtextures[i][0] = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_FULLBRIGHT); } else { pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD); pheader->fbtextures[i][0] = NULL; } pheader->gltextures[i][3] = pheader->gltextures[i][2] = pheader->gltextures[i][1] = pheader->gltextures[i][0]; pheader->fbtextures[i][3] = pheader->fbtextures[i][2] = pheader->fbtextures[i][1] = pheader->fbtextures[i][0]; //johnfitz pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + size); } else { // animating skin group. yuck. pskintype++; pinskingroup = (daliasskingroup_t *)pskintype; groupskins = LittleLong (pinskingroup->numskins); pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1); pskintype = (daliasskintype_t *)(pinskinintervals + groupskins); for (j=0 ; j<groupskins ; j++) { Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight ); if (j == 0) { texels = (byte *) Hunk_AllocName(size, loadname); pheader->texels[i] = texels - (byte *)pheader; memcpy (texels, (byte *)(pskintype), size); } //johnfitz -- rewritten q_snprintf (name, sizeof(name), "%s:frame%i_%i", loadmodel->name, i,j); offset = (src_offset_t)(pskintype) - (src_offset_t)mod_base; //johnfitz if (Mod_CheckFullbrights ((byte *)(pskintype), size)) { pheader->gltextures[i][j&3] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_NOBRIGHT); q_snprintf (fbr_mask_name, sizeof(fbr_mask_name), "%s:frame%i_%i_glow", loadmodel->name, i,j); pheader->fbtextures[i][j&3] = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_FULLBRIGHT); } else { pheader->gltextures[i][j&3] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD); pheader->fbtextures[i][j&3] = NULL; } //johnfitz pskintype = (daliasskintype_t *)((byte *)(pskintype) + size); } k = j; for (/**/; j < 4; j++) pheader->gltextures[i][j&3] = pheader->gltextures[i][j - k]; } } return (void *)pskintype; } //========================================================================= /* ================= Mod_CalcAliasBounds -- johnfitz -- calculate bounds of alias model for nonrotated, yawrotated, and fullrotated cases ================= */ void Mod_CalcAliasBounds (aliashdr_t *a) { int i,j,k; float dist, yawradius, radius; vec3_t v; //clear out all data for (i=0; i<3;i++) { loadmodel->mins[i] = loadmodel->ymins[i] = loadmodel->rmins[i] = 999999; loadmodel->maxs[i] = loadmodel->ymaxs[i] = loadmodel->rmaxs[i] = -999999; radius = yawradius = 0; } //process verts for (i=0 ; i<a->numposes; i++) for (j=0; j<a->numverts; j++) { for (k=0; k<3;k++) v[k] = poseverts[i][j].v[k] * pheader->scale[k] + pheader->scale_origin[k]; for (k=0; k<3;k++) { loadmodel->mins[k] = q_min(loadmodel->mins[k], v[k]); loadmodel->maxs[k] = q_max(loadmodel->maxs[k], v[k]); } dist = v[0] * v[0] + v[1] * v[1]; if (yawradius < dist) yawradius = dist; dist += v[2] * v[2]; if (radius < dist) radius = dist; } //rbounds will be used when entity has nonzero pitch or roll radius = sqrt(radius); loadmodel->rmins[0] = loadmodel->rmins[1] = loadmodel->rmins[2] = -radius; loadmodel->rmaxs[0] = loadmodel->rmaxs[1] = loadmodel->rmaxs[2] = radius; //ybounds will be used when entity has nonzero yaw yawradius = sqrt(yawradius); loadmodel->ymins[0] = loadmodel->ymins[1] = -yawradius; loadmodel->ymaxs[0] = loadmodel->ymaxs[1] = yawradius; loadmodel->ymins[2] = loadmodel->mins[2]; loadmodel->ymaxs[2] = loadmodel->maxs[2]; } static qboolean nameInList(const char *list, const char *name) { const char *s; char tmp[MAX_QPATH]; int i; s = list; while (*s) { // make a copy until the next comma or end of string i = 0; while (*s && *s != ',') { if (i < MAX_QPATH - 1) tmp[i++] = *s; s++; } tmp[i] = '\0'; //compare it to the model name if (!strcmp(name, tmp)) { return true; } //search forwards to the next comma or end of string while (*s && *s == ',') s++; } return false; } /* ================= Mod_SetExtraFlags -- johnfitz -- set up extra flags that aren't in the mdl ================= */ void Mod_SetExtraFlags (qmodel_t *mod) { extern cvar_t r_nolerp_list, r_noshadow_list; if (!mod || !mod->name || mod->type != mod_alias) return; mod->flags &= 0xFF; //only preserve first byte // nolerp flag if (nameInList(r_nolerp_list.string, mod->name)) mod->flags |= MOD_NOLERP; // noshadow flag if (nameInList(r_noshadow_list.string, mod->name)) mod->flags |= MOD_NOSHADOW; // fullbright hack (TODO: make this a cvar list) if (!strcmp (mod->name, "progs/flame2.mdl") || !strcmp (mod->name, "progs/flame.mdl") || !strcmp (mod->name, "progs/boss.mdl")) mod->flags |= MOD_FBRIGHTHACK; } /* ================= Mod_LoadAliasModel ================= */ void Mod_LoadAliasModel (qmodel_t *mod, void *buffer) { int i, j; mdl_t *pinmodel; stvert_t *pinstverts; dtriangle_t *pintriangles; int version, numframes; int size; daliasframetype_t *pframetype; daliasskintype_t *pskintype; int start, end, total; start = Hunk_LowMark (); pinmodel = (mdl_t *)buffer; mod_base = (byte *)buffer; //johnfitz version = LittleLong (pinmodel->version); if (version != ALIAS_VERSION) Sys_Error ("%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_VERSION); // // allocate space for a working header, plus all the data except the frames, // skin and group info // size = sizeof(aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * sizeof (pheader->frames[0]); pheader = (aliashdr_t *) Hunk_AllocName (size, loadname); mod->flags = LittleLong (pinmodel->flags); // // endian-adjust and copy the data, starting with the alias model header // pheader->boundingradius = LittleFloat (pinmodel->boundingradius); pheader->numskins = LittleLong (pinmodel->numskins); pheader->skinwidth = LittleLong (pinmodel->skinwidth); pheader->skinheight = LittleLong (pinmodel->skinheight); if (pheader->skinheight > MAX_LBM_HEIGHT) Sys_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); pheader->numverts = LittleLong (pinmodel->numverts); if (pheader->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); if (pheader->numverts > MAXALIASVERTS) Sys_Error ("model %s has too many vertices", mod->name); pheader->numtris = LittleLong (pinmodel->numtris); if (pheader->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); pheader->numframes = LittleLong (pinmodel->numframes); numframes = pheader->numframes; if (numframes < 1) Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; mod->synctype = (synctype_t) LittleLong (pinmodel->synctype); mod->numframes = pheader->numframes; for (i=0 ; i<3 ; i++) { pheader->scale[i] = LittleFloat (pinmodel->scale[i]); pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]); pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]); } // // load the skins // pskintype = (daliasskintype_t *)&pinmodel[1]; pskintype = (daliasskintype_t *) Mod_LoadAllSkins (pheader->numskins, pskintype); // // load base s and t vertices // pinstverts = (stvert_t *)pskintype; for (i=0 ; i<pheader->numverts ; i++) { stverts[i].onseam = LittleLong (pinstverts[i].onseam); stverts[i].s = LittleLong (pinstverts[i].s); stverts[i].t = LittleLong (pinstverts[i].t); } // // load triangle lists // pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts]; for (i=0 ; i<pheader->numtris ; i++) { triangles[i].facesfront = LittleLong (pintriangles[i].facesfront); for (j=0 ; j<3 ; j++) { triangles[i].vertindex[j] = LittleLong (pintriangles[i].vertindex[j]); } } // // load the frames // posenum = 0; pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris]; for (i=0 ; i<numframes ; i++) { aliasframetype_t frametype; frametype = (aliasframetype_t) LittleLong (pframetype->type); if (frametype == ALIAS_SINGLE) pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]); else pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]); } pheader->numposes = posenum; mod->type = mod_alias; Mod_SetExtraFlags (mod); //johnfitz Mod_CalcAliasBounds (pheader); //johnfitz // // build the draw lists // GL_MakeAliasModelDisplayLists (mod, pheader); // // move the complete, relocatable alias model to the cache // end = Hunk_LowMark (); total = end - start; Cache_Alloc (&mod->cache, total, loadname); if (!mod->cache.data) return; memcpy (mod->cache.data, pheader, total); Hunk_FreeToLowMark (start); } //============================================================================= /* ================= Mod_LoadSpriteFrame ================= */ void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum) { dspriteframe_t *pinframe; mspriteframe_t *pspriteframe; int width, height, size, origin[2]; char name[64]; src_offset_t offset; //johnfitz pinframe = (dspriteframe_t *)pin; width = LittleLong (pinframe->width); height = LittleLong (pinframe->height); size = width * height; pspriteframe = (mspriteframe_t *) Hunk_AllocName (sizeof (mspriteframe_t),loadname); *ppframe = pspriteframe; pspriteframe->width = width; pspriteframe->height = height; origin[0] = LittleLong (pinframe->origin[0]); origin[1] = LittleLong (pinframe->origin[1]); pspriteframe->up = origin[1]; pspriteframe->down = origin[1] - height; pspriteframe->left = origin[0]; pspriteframe->right = width + origin[0]; //johnfitz -- image might be padded pspriteframe->smax = (float)width/(float)TexMgr_PadConditional(width); pspriteframe->tmax = (float)height/(float)TexMgr_PadConditional(height); //johnfitz q_snprintf (name, sizeof(name), "%s:frame%i", loadmodel->name, framenum); offset = (src_offset_t)(pinframe+1) - (src_offset_t)mod_base; //johnfitz pspriteframe->gltexture = TexMgr_LoadImage (loadmodel, name, width, height, SRC_INDEXED, (byte *)(pinframe + 1), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_ALPHA | TEXPREF_NOPICMIP); //johnfitz -- TexMgr return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size); } /* ================= Mod_LoadSpriteGroup ================= */ void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum) { dspritegroup_t *pingroup; mspritegroup_t *pspritegroup; int i, numframes; dspriteinterval_t *pin_intervals; float *poutintervals; void *ptemp; pingroup = (dspritegroup_t *)pin; numframes = LittleLong (pingroup->numframes); pspritegroup = (mspritegroup_t *) Hunk_AllocName (sizeof (mspritegroup_t) + (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname); pspritegroup->numframes = numframes; *ppframe = (mspriteframe_t *)pspritegroup; pin_intervals = (dspriteinterval_t *)(pingroup + 1); poutintervals = (float *) Hunk_AllocName (numframes * sizeof (float), loadname); pspritegroup->intervals = poutintervals; for (i=0 ; i<numframes ; i++) { *poutintervals = LittleFloat (pin_intervals->interval); if (*poutintervals <= 0.0) Sys_Error ("Mod_LoadSpriteGroup: interval<=0"); poutintervals++; pin_intervals++; } ptemp = (void *)pin_intervals; for (i=0 ; i<numframes ; i++) { ptemp = Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i], framenum * 100 + i); } return ptemp; } /* ================= Mod_LoadSpriteModel ================= */ void Mod_LoadSpriteModel (qmodel_t *mod, void *buffer) { int i; int version; dsprite_t *pin; msprite_t *psprite; int numframes; int size; dspriteframetype_t *pframetype; pin = (dsprite_t *)buffer; mod_base = (byte *)buffer; //johnfitz version = LittleLong (pin->version); if (version != SPRITE_VERSION) Sys_Error ("%s has wrong version number " "(%i should be %i)", mod->name, version, SPRITE_VERSION); numframes = LittleLong (pin->numframes); size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); psprite = (msprite_t *) Hunk_AllocName (size, loadname); mod->cache.data = psprite; psprite->type = LittleLong (pin->type); psprite->maxwidth = LittleLong (pin->width); psprite->maxheight = LittleLong (pin->height); psprite->beamlength = LittleFloat (pin->beamlength); mod->synctype = (synctype_t) LittleLong (pin->synctype); psprite->numframes = numframes; mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2; mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2; mod->mins[2] = -psprite->maxheight/2; mod->maxs[2] = psprite->maxheight/2; // // load the frames // if (numframes < 1) Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); mod->numframes = numframes; pframetype = (dspriteframetype_t *)(pin + 1); for (i=0 ; i<numframes ; i++) { spriteframetype_t frametype; frametype = (spriteframetype_t) LittleLong (pframetype->type); psprite->frames[i].type = frametype; if (frametype == SPR_SINGLE) { pframetype = (dspriteframetype_t *) Mod_LoadSpriteFrame (pframetype + 1, &psprite->frames[i].frameptr, i); } else { pframetype = (dspriteframetype_t *) Mod_LoadSpriteGroup (pframetype + 1, &psprite->frames[i].frameptr, i); } } mod->type = mod_sprite; } //============================================================================= /* ================ Mod_Print ================ */ void Mod_Print (void) { int i; qmodel_t *mod; Con_SafePrintf ("Cached models:\n"); //johnfitz -- safeprint instead of print for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) { Con_SafePrintf ("%8p : %s\n", mod->cache.data, mod->name); //johnfitz -- safeprint instead of print } Con_Printf ("%i models\n",mod_numknown); //johnfitz -- print the total too } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cl_tent.c�������������������������������������������������������������������0000644�0000000�0000000�00000020316�12407762022�015317� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cl_tent.c -- client side temporary entities #include "quakedef.h" int num_temp_entities; entity_t cl_temp_entities[MAX_TEMP_ENTITIES]; beam_t cl_beams[MAX_BEAMS]; sfx_t *cl_sfx_wizhit; sfx_t *cl_sfx_knighthit; sfx_t *cl_sfx_tink1; sfx_t *cl_sfx_ric1; sfx_t *cl_sfx_ric2; sfx_t *cl_sfx_ric3; sfx_t *cl_sfx_r_exp3; /* ================= CL_ParseTEnt ================= */ void CL_InitTEnts (void) { cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav"); cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav"); cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav"); cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); } /* ================= CL_ParseBeam ================= */ void CL_ParseBeam (qmodel_t *m) { int ent; vec3_t start, end; beam_t *b; int i; ent = MSG_ReadShort (); start[0] = MSG_ReadCoord (); start[1] = MSG_ReadCoord (); start[2] = MSG_ReadCoord (); end[0] = MSG_ReadCoord (); end[1] = MSG_ReadCoord (); end[2] = MSG_ReadCoord (); // override any beam with the same entity for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) if (b->entity == ent) { b->entity = ent; b->model = m; b->endtime = cl.time + 0.2; VectorCopy (start, b->start); VectorCopy (end, b->end); return; } // find a free beam for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) { if (!b->model || b->endtime < cl.time) { b->entity = ent; b->model = m; b->endtime = cl.time + 0.2; VectorCopy (start, b->start); VectorCopy (end, b->end); return; } } //johnfitz -- less spammy overflow message if (!dev_overflows.beams || dev_overflows.beams + CONSOLE_RESPAM_TIME < realtime ) { Con_Printf ("Beam list overflow!\n"); dev_overflows.beams = realtime; } //johnfitz } /* ================= CL_ParseTEnt ================= */ void CL_ParseTEnt (void) { int type; vec3_t pos; dlight_t *dl; int rnd; int colorStart, colorLength; type = MSG_ReadByte (); switch (type) { case TE_WIZSPIKE: // spike hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 20, 30); S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1); break; case TE_KNIGHTSPIKE: // spike hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 226, 20); S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1); break; case TE_SPIKE: // spike hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 0, 10); if ( rand() % 5 ) S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1); else { rnd = rand() & 3; if (rnd == 1) S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1); else if (rnd == 2) S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1); else S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1); } break; case TE_SUPERSPIKE: // super spike hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 0, 20); if ( rand() % 5 ) S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1); else { rnd = rand() & 3; if (rnd == 1) S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1); else if (rnd == 2) S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1); else S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1); } break; case TE_GUNSHOT: // bullet hitting wall pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_RunParticleEffect (pos, vec3_origin, 0, 20); break; case TE_EXPLOSION: // rocket explosion pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_ParticleExplosion (pos); dl = CL_AllocDlight (0); VectorCopy (pos, dl->origin); dl->radius = 350; dl->die = cl.time + 0.5; dl->decay = 300; S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); break; case TE_TAREXPLOSION: // tarbaby explosion pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_BlobExplosion (pos); S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); break; case TE_LIGHTNING1: // lightning bolts CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true)); break; case TE_LIGHTNING2: // lightning bolts CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true)); break; case TE_LIGHTNING3: // lightning bolts CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true)); break; // PGM 01/21/97 case TE_BEAM: // grappling hook beam CL_ParseBeam (Mod_ForName("progs/beam.mdl", true)); break; // PGM 01/21/97 case TE_LAVASPLASH: pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_LavaSplash (pos); break; case TE_TELEPORT: pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); R_TeleportSplash (pos); break; case TE_EXPLOSION2: // color mapped explosion pos[0] = MSG_ReadCoord (); pos[1] = MSG_ReadCoord (); pos[2] = MSG_ReadCoord (); colorStart = MSG_ReadByte (); colorLength = MSG_ReadByte (); R_ParticleExplosion2 (pos, colorStart, colorLength); dl = CL_AllocDlight (0); VectorCopy (pos, dl->origin); dl->radius = 350; dl->die = cl.time + 0.5; dl->decay = 300; S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); break; default: Sys_Error ("CL_ParseTEnt: bad type"); } } /* ================= CL_NewTempEntity ================= */ entity_t *CL_NewTempEntity (void) { entity_t *ent; if (cl_numvisedicts == MAX_VISEDICTS) return NULL; if (num_temp_entities == MAX_TEMP_ENTITIES) return NULL; ent = &cl_temp_entities[num_temp_entities]; memset (ent, 0, sizeof(*ent)); num_temp_entities++; cl_visedicts[cl_numvisedicts] = ent; cl_numvisedicts++; ent->colormap = vid.colormap; return ent; } /* ================= CL_UpdateTEnts ================= */ void CL_UpdateTEnts (void) { int i, j; //johnfitz -- use j instead of using i twice, so we don't corrupt memory beam_t *b; vec3_t dist, org; float d; entity_t *ent; float yaw, pitch; float forward; num_temp_entities = 0; srand ((int) (cl.time * 1000)); //johnfitz -- freeze beams when paused // update lightning for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) { if (!b->model || b->endtime < cl.time) continue; // if coming from the player, update the start position if (b->entity == cl.viewentity) { VectorCopy (cl_entities[cl.viewentity].origin, b->start); } // calculate pitch and yaw VectorSubtract (b->end, b->start, dist); if (dist[1] == 0 && dist[0] == 0) { yaw = 0; if (dist[2] > 0) pitch = 90; else pitch = 270; } else { yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI); if (yaw < 0) yaw += 360; forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); pitch = (int) (atan2(dist[2], forward) * 180 / M_PI); if (pitch < 0) pitch += 360; } // add new entities for the lightning VectorCopy (b->start, org); d = VectorNormalize(dist); while (d > 0) { ent = CL_NewTempEntity (); if (!ent) return; VectorCopy (org, ent->origin); ent->model = b->model; ent->angles[0] = pitch; ent->angles[1] = yaw; ent->angles[2] = rand()%360; //johnfitz -- use j instead of using i twice, so we don't corrupt memory for (j=0 ; j<3 ; j++) org[j] += dist[j]*30; d -= 30; } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/build_cross_win64.sh��������������������������������������������������������0000755�0000000�0000000�00000000670�12475156650�017433� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # Change this script to meet your needs and/or environment. TARGET=x86_64-w64-mingw32 PREFIX=/opt/cross_win64 PATH="$PREFIX/bin:$PATH" export PATH MAKE_CMD=make CC="$TARGET-gcc" AS="$TARGET-as" RANLIB="$TARGET-ranlib" AR="$TARGET-ar" WINDRES="$TARGET-windres" STRIP="$TARGET-strip" export PATH CC AS AR RANLIB WINDRES STRIP exec $MAKE_CMD CC=$CC AS=$AS RANLIB=$RANLIB AR=$AR WINDRES=$WINDRES STRIP=$STRIP -f Makefile.w64 $* ������������������������������������������������������������������������quakespasm-0.91.0/Quake/cd_null.c�������������������������������������������������������������������0000644�0000000�0000000�00000002065�12407762022�015310� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * cd_null.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 */ #include "quakedef.h" int CDAudio_Play(byte track, qboolean looping) { return -1; } void CDAudio_Stop(void) { } void CDAudio_Pause(void) { } void CDAudio_Resume(void) { } void CDAudio_Update(void) { } int CDAudio_Init(void) { Con_Printf("CDAudio disabled at compile time\n"); return -1; } void CDAudio_Shutdown(void) { } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/q_stdinc.h������������������������������������������������������������������0000644�0000000�0000000�00000013476�12424704230�015505� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * q_stdinc.h - includes the minimum necessary stdc headers, * defines common and / or missing types. * * NOTE: for net stuff use net_sys.h, * for byte order use q_endian.h, * for math stuff use mathlib.h, * for locale-insensitive ctype.h functions use q_ctype.h. * * Copyright (C) 1996-1997 Id Software, Inc. * Copyright (C) 2007-2011 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #ifndef __QSTDINC_H #define __QSTDINC_H #include <sys/types.h> #include <stddef.h> #include <limits.h> #ifndef _WIN32 /* others we support without sys/param.h? */ #include <sys/param.h> #endif /* NOTES on TYPE SIZES: Quake/Hexen II engine relied on 32 bit int type size with ILP32 (not LP32) model in mind. We now support LP64 and LLP64, too. We expect: sizeof (char) == 1 sizeof (short) == 2 sizeof (int) == 4 sizeof (float) == 4 sizeof (long) == 4 / 8 sizeof (pointer *) == 4 / 8 For this, we need stdint.h (or inttypes.h) FIXME: On some platforms, only inttypes.h is available. FIXME: Properly replace certain short and int usage with int16_t and int32_t. */ #if defined(_MSC_VER) && (_MSC_VER < 1600) /* MS Visual Studio provides stdint.h only starting with * version 2010. Even in VS2010, there is no inttypes.h.. */ #include "msinttypes/stdint.h" #else #include <stdint.h> #endif #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> /*==========================================================================*/ #ifndef NULL #if defined(__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif #endif #define Q_MAXCHAR ((char)0x7f) #define Q_MAXSHORT ((short)0x7fff) #define Q_MAXINT ((int)0x7fffffff) #define Q_MAXLONG ((int)0x7fffffff) #define Q_MAXFLOAT ((int)0x7fffffff) #define Q_MINCHAR ((char)0x80) #define Q_MINSHORT ((short)0x8000) #define Q_MININT ((int)0x80000000) #define Q_MINLONG ((int)0x80000000) #define Q_MINFLOAT ((int)0x7fffffff) /* Make sure the types really have the right * sizes: These macros are from SDL headers. */ #define COMPILE_TIME_ASSERT(name, x) \ typedef int dummy_ ## name[(x) * 2 - 1] COMPILE_TIME_ASSERT(char, sizeof(char) == 1); COMPILE_TIME_ASSERT(float, sizeof(float) == 4); COMPILE_TIME_ASSERT(long, sizeof(long) >= 4); COMPILE_TIME_ASSERT(int, sizeof(int) == 4); COMPILE_TIME_ASSERT(short, sizeof(short) == 2); /* make sure enums are the size of ints for structure packing */ typedef enum { THE_DUMMY_VALUE } THE_DUMMY_ENUM; COMPILE_TIME_ASSERT(enum, sizeof(THE_DUMMY_ENUM) == sizeof(int)); /* Provide a substitute for offsetof() if we don't have one. * This variant works on most (but not *all*) systems... */ #ifndef offsetof #define offsetof(t,m) ((size_t)&(((t *)0)->m)) #endif /*==========================================================================*/ typedef unsigned char byte; #undef true #undef false #if defined(__cplusplus) /* some structures have qboolean members and the x86 asm code expect * those members to be 4 bytes long. therefore, qboolean must be 32 * bits and it can NOT be binary compatible with the 8 bit C++ bool. */ typedef int qboolean; COMPILE_TIME_ASSERT(falsehood, (0 == false)); COMPILE_TIME_ASSERT(truth, (1 == true)); #else typedef enum { false = 0, true = 1 } qboolean; COMPILE_TIME_ASSERT(falsehood, ((1 != 1) == false)); COMPILE_TIME_ASSERT(truth, ((1 == 1) == true)); #endif COMPILE_TIME_ASSERT(qboolean, sizeof(qboolean) == 4); /*==========================================================================*/ /* math */ typedef float vec_t; typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4]; typedef vec_t vec5_t[5]; typedef int fixed4_t; typedef int fixed8_t; typedef int fixed16_t; /*==========================================================================*/ /* MAX_OSPATH (max length of a filesystem pathname, i.e. PATH_MAX) * Note: See GNU Hurd and others' notes about brokenness of this: * http://www.gnu.org/software/hurd/community/gsoc/project_ideas/maxpath.html * http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html */ #if !defined(PATH_MAX) /* equivalent values? */ #if defined(MAXPATHLEN) #define PATH_MAX MAXPATHLEN #elif defined(_WIN32) && defined(_MAX_PATH) #define PATH_MAX _MAX_PATH #elif defined(_WIN32) && defined(MAX_PATH) #define PATH_MAX MAX_PATH #else /* fallback */ #define PATH_MAX 1024 #endif #endif /* PATH_MAX */ #define MAX_OSPATH PATH_MAX /*==========================================================================*/ /* missing types */ #if defined(_MSC_VER) #if defined(_WIN64) #define ssize_t SSIZE_T #else typedef int ssize_t; #endif /* _WIN64 */ #endif /* _MSC_VER */ /*==========================================================================*/ #if !defined(__GNUC__) #define __attribute__(x) #endif /* __GNUC__ */ /* argument format attributes for function * pointers are supported for gcc >= 3.1 */ #if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)) #define __fp_attribute__ __attribute__ #else #define __fp_attribute__(x) #endif #if defined(_MSC_VER) && !defined(__cplusplus) #define inline __inline #endif /* _MSC_VER */ /*==========================================================================*/ #endif /* __QSTDINC_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/crc.h�����������������������������������������������������������������������0000644�0000000�0000000�00000002105�11340073704�014434� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_CRC_H #define _QUAKE_CRC_H /* crc.h */ void CRC_Init(unsigned short *crcvalue); void CRC_ProcessByte(unsigned short *crcvalue, byte data); unsigned short CRC_Value(unsigned short crcvalue); unsigned short CRC_Block (byte *start, int count); //johnfitz -- texture crc #endif /* _QUAKE_CRC_H */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/glquake.h�������������������������������������������������������������������0000644�0000000�0000000�00000033223�12625545642�015337� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __GLQUAKE_H #define __GLQUAKE_H void GL_BeginRendering (int *x, int *y, int *width, int *height); void GL_EndRendering (void); void GL_Set2D (void); extern int glx, gly, glwidth, glheight; // r_local.h -- private refresh defs #define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0) // normalizing factor so player model works out to about // 1 pixel per triangle #define MAX_LBM_HEIGHT 480 #define TILE_SIZE 128 // size of textures generated by R_GenTiledSurf #define SKYSHIFT 7 #define SKYSIZE (1 << SKYSHIFT) #define SKYMASK (SKYSIZE - 1) #define BACKFACE_EPSILON 0.01 void R_TimeRefresh_f (void); void R_ReadPointFile_f (void); texture_t *R_TextureAnimation (texture_t *base, int frame); typedef struct surfcache_s { struct surfcache_s *next; struct surfcache_s **owner; // NULL is an empty chunk of memory int lightadj[MAXLIGHTMAPS]; // checked for strobe flush int dlight; int size; // including header unsigned width; unsigned height; // DEBUG only needed for debug float mipscale; struct texture_s *texture; // checked for animating textures byte data[4]; // width*height elements } surfcache_t; typedef struct { pixel_t *surfdat; // destination for generated surface int rowbytes; // destination logical width in bytes msurface_t *surf; // description for surface to generate fixed8_t lightadj[MAXLIGHTMAPS]; // adjust for lightmap levels for dynamic lighting texture_t *texture; // corrected for animating textures int surfmip; // mipmapped ratio of surface texels / world pixels int surfwidth; // in mipmapped texels int surfheight; // in mipmapped texels } drawsurf_t; typedef enum { pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2 } ptype_t; // !!! if this is changed, it must be changed in d_ifacea.h too !!! typedef struct particle_s { // driver-usable fields vec3_t org; float color; // drivers never touch the following fields struct particle_s *next; vec3_t vel; float ramp; float die; ptype_t type; } particle_t; //==================================================== extern qboolean r_cache_thrash; // compatability extern vec3_t modelorg, r_entorigin; extern entity_t *currententity; extern int r_visframecount; // ??? what difs? extern int r_framecount; extern mplane_t frustum[4]; // // view origin // extern vec3_t vup; extern vec3_t vpn; extern vec3_t vright; extern vec3_t r_origin; // // screen size info // extern refdef_t r_refdef; extern mleaf_t *r_viewleaf, *r_oldviewleaf; extern int d_lightstylevalue[256]; // 8.8 fraction of base light value extern cvar_t r_norefresh; extern cvar_t r_drawentities; extern cvar_t r_drawworld; extern cvar_t r_drawviewmodel; extern cvar_t r_speeds; extern cvar_t r_pos; extern cvar_t r_waterwarp; extern cvar_t r_fullbright; extern cvar_t r_lightmap; extern cvar_t r_shadows; extern cvar_t r_wateralpha; extern cvar_t r_lavaalpha; extern cvar_t r_telealpha; extern cvar_t r_slimealpha; extern cvar_t r_dynamic; extern cvar_t r_novis; extern cvar_t gl_clear; extern cvar_t gl_cull; extern cvar_t gl_smoothmodels; extern cvar_t gl_affinemodels; extern cvar_t gl_polyblend; extern cvar_t gl_flashblend; extern cvar_t gl_nocolors; extern cvar_t gl_playermip; extern cvar_t gl_subdivide_size; extern float load_subdivide_size; //johnfitz -- remember what subdivide_size value was when this map was loaded extern int gl_stencilbits; // Multitexture extern qboolean mtexenabled; extern qboolean gl_mtexable; extern PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc; extern PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc; extern PFNGLCLIENTACTIVETEXTUREARBPROC GL_ClientActiveTextureFunc; extern GLint gl_max_texture_units; //ericw //johnfitz -- anisotropic filtering #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF extern float gl_max_anisotropy; extern qboolean gl_anisotropy_able; //ericw -- VBO extern PFNGLBINDBUFFERARBPROC GL_BindBufferFunc; extern PFNGLBUFFERDATAARBPROC GL_BufferDataFunc; extern PFNGLBUFFERSUBDATAARBPROC GL_BufferSubDataFunc; extern PFNGLDELETEBUFFERSARBPROC GL_DeleteBuffersFunc; extern PFNGLGENBUFFERSARBPROC GL_GenBuffersFunc; extern qboolean gl_vbo_able; //ericw //ericw -- GLSL // SDL 1.2 has a bug where it doesn't provide these typedefs on OS X! typedef GLuint (APIENTRYP QS_PFNGLCREATESHADERPROC) (GLenum type); typedef void (APIENTRYP QS_PFNGLDELETESHADERPROC) (GLuint shader); typedef void (APIENTRYP QS_PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP QS_PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); typedef void (APIENTRYP QS_PFNGLCOMPILESHADERPROC) (GLuint shader); typedef void (APIENTRYP QS_PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (APIENTRYP QS_PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP QS_PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (APIENTRYP QS_PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef GLuint (APIENTRYP QS_PFNGLCREATEPROGRAMPROC) (void); typedef void (APIENTRYP QS_PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP QS_PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (APIENTRYP QS_PFNGLBINDATTRIBLOCATIONFUNC) (GLuint program, GLuint index, const GLchar *name); typedef void (APIENTRYP QS_PFNGLUSEPROGRAMPROC) (GLuint program); typedef GLint (APIENTRYP QS_PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP QS_PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); typedef void (APIENTRYP QS_PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP QS_PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef GLint (APIENTRYP QS_PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP QS_PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (APIENTRYP QS_PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP QS_PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP QS_PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); extern QS_PFNGLCREATESHADERPROC GL_CreateShaderFunc; extern QS_PFNGLDELETESHADERPROC GL_DeleteShaderFunc; extern QS_PFNGLDELETEPROGRAMPROC GL_DeleteProgramFunc; extern QS_PFNGLSHADERSOURCEPROC GL_ShaderSourceFunc; extern QS_PFNGLCOMPILESHADERPROC GL_CompileShaderFunc; extern QS_PFNGLGETSHADERIVPROC GL_GetShaderivFunc; extern QS_PFNGLGETSHADERINFOLOGPROC GL_GetShaderInfoLogFunc; extern QS_PFNGLGETPROGRAMIVPROC GL_GetProgramivFunc; extern QS_PFNGLGETPROGRAMINFOLOGPROC GL_GetProgramInfoLogFunc; extern QS_PFNGLCREATEPROGRAMPROC GL_CreateProgramFunc; extern QS_PFNGLATTACHSHADERPROC GL_AttachShaderFunc; extern QS_PFNGLLINKPROGRAMPROC GL_LinkProgramFunc; extern QS_PFNGLBINDATTRIBLOCATIONFUNC GL_BindAttribLocationFunc; extern QS_PFNGLUSEPROGRAMPROC GL_UseProgramFunc; extern QS_PFNGLGETATTRIBLOCATIONPROC GL_GetAttribLocationFunc; extern QS_PFNGLVERTEXATTRIBPOINTERPROC GL_VertexAttribPointerFunc; extern QS_PFNGLENABLEVERTEXATTRIBARRAYPROC GL_EnableVertexAttribArrayFunc; extern QS_PFNGLDISABLEVERTEXATTRIBARRAYPROC GL_DisableVertexAttribArrayFunc; extern QS_PFNGLGETUNIFORMLOCATIONPROC GL_GetUniformLocationFunc; extern QS_PFNGLUNIFORM1IPROC GL_Uniform1iFunc; extern QS_PFNGLUNIFORM1FPROC GL_Uniform1fFunc; extern QS_PFNGLUNIFORM3FPROC GL_Uniform3fFunc; extern QS_PFNGLUNIFORM4FPROC GL_Uniform4fFunc; extern qboolean gl_glsl_able; extern qboolean gl_glsl_gamma_able; extern qboolean gl_glsl_alias_able; // ericw -- //ericw -- NPOT texture support extern qboolean gl_texture_NPOT; //johnfitz -- polygon offset #define OFFSET_BMODEL 1 #define OFFSET_NONE 0 #define OFFSET_DECAL -1 #define OFFSET_FOG -2 #define OFFSET_SHOWTRIS -3 void GL_PolygonOffset (int); //johnfitz -- GL_EXT_texture_env_combine //the values for GL_ARB_ are identical #define GL_COMBINE_EXT 0x8570 #define GL_COMBINE_RGB_EXT 0x8571 #define GL_COMBINE_ALPHA_EXT 0x8572 #define GL_RGB_SCALE_EXT 0x8573 #define GL_CONSTANT_EXT 0x8576 #define GL_PRIMARY_COLOR_EXT 0x8577 #define GL_PREVIOUS_EXT 0x8578 #define GL_SOURCE0_RGB_EXT 0x8580 #define GL_SOURCE1_RGB_EXT 0x8581 #define GL_SOURCE0_ALPHA_EXT 0x8588 #define GL_SOURCE1_ALPHA_EXT 0x8589 extern qboolean gl_texture_env_combine; extern qboolean gl_texture_env_add; // for GL_EXT_texture_env_add //johnfitz -- rendering statistics extern int rs_brushpolys, rs_aliaspolys, rs_skypolys, rs_particles, rs_fogpolys; extern int rs_dynamiclightmaps, rs_brushpasses, rs_aliaspasses, rs_skypasses; extern float rs_megatexels; //johnfitz -- track developer statistics that vary every frame extern cvar_t devstats; typedef struct { int packetsize; int edicts; int visedicts; int efrags; int tempents; int beams; int dlights; } devstats_t; extern devstats_t dev_stats, dev_peakstats; //ohnfitz -- reduce overflow warning spam typedef struct { double packetsize; double efrags; double beams; } overflowtimes_t; extern overflowtimes_t dev_overflows; //this stores the last time overflow messages were displayed, not the last time overflows occured #define CONSOLE_RESPAM_TIME 3 // seconds between repeated warning messages //johnfitz -- moved here from r_brush.c extern int gl_lightmap_format, lightmap_bytes; #define MAX_LIGHTMAPS 256 //johnfitz -- was 64 extern gltexture_t *lightmap_textures[MAX_LIGHTMAPS]; //johnfitz -- changed to an array extern int gl_warpimagesize; //johnfitz -- for water warp extern qboolean r_drawflat_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe, r_drawworld_cheatsafe; //johnfitz typedef struct glsl_attrib_binding_s { const char *name; GLuint attrib; } glsl_attrib_binding_t; extern float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha; //ericw //johnfitz -- fog functions called from outside gl_fog.c void Fog_ParseServerMessage (void); float *Fog_GetColor (void); float Fog_GetDensity (void); void Fog_EnableGFog (void); void Fog_DisableGFog (void); void Fog_StartAdditive (void); void Fog_StopAdditive (void); void Fog_SetupFrame (void); void Fog_NewMap (void); void Fog_Init (void); void Fog_SetupState (void); void R_NewGame (void); void R_AnimateLight (void); void R_MarkSurfaces (void); void R_CullSurfaces (void); qboolean R_CullBox (vec3_t emins, vec3_t emaxs); void R_StoreEfrags (efrag_t **ppefrag); qboolean R_CullModelForEntity (entity_t *e); void R_RotateForEntity (vec3_t origin, vec3_t angles); void R_MarkLights (dlight_t *light, int num, mnode_t *node); void R_InitParticles (void); void R_DrawParticles (void); void CL_RunParticles (void); void R_ClearParticles (void); void R_TranslatePlayerSkin (int playernum); void R_TranslateNewPlayerSkin (int playernum); //johnfitz -- this handles cases when the actual texture changes void R_UpdateWarpTextures (void); void R_DrawWorld (void); void R_DrawAliasModel (entity_t *e); void R_DrawBrushModel (entity_t *e); void R_DrawSpriteModel (entity_t *e); void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain); void R_RenderDlights (void); void GL_BuildLightmaps (void); void GL_DeleteBModelVertexBuffer (void); void GL_BuildBModelVertexBuffer (void); void GLMesh_LoadVertexBuffers (void); void GLMesh_DeleteVertexBuffers (void); void R_RebuildAllLightmaps (void); int R_LightPoint (vec3_t p); void GL_SubdivideSurface (msurface_t *fa); void R_BuildLightMap (msurface_t *surf, byte *dest, int stride); void R_RenderDynamicLightmaps (msurface_t *fa); void R_UploadLightmaps (void); void R_DrawWorld_ShowTris (void); void R_DrawBrushModel_ShowTris (entity_t *e); void R_DrawAliasModel_ShowTris (entity_t *e); void R_DrawParticles_ShowTris (void); GLint GL_GetUniformLocation (GLuint *programPtr, const char *name); GLuint GL_CreateProgram (const GLchar *vertSource, const GLchar *fragSource, int numbindings, const glsl_attrib_binding_t *bindings); void R_DeleteShaders (void); void GLAlias_CreateShaders (void); void GL_DrawAliasShadow (entity_t *e); void DrawGLTriangleFan (glpoly_t *p); void DrawGLPoly (glpoly_t *p); void DrawWaterPoly (glpoly_t *p); void GL_MakeAliasModelDisplayLists (qmodel_t *m, aliashdr_t *hdr); void Sky_Init (void); void Sky_DrawSky (void); void Sky_NewMap (void); void Sky_LoadTexture (texture_t *mt); void Sky_LoadSkyBox (const char *name); void TexMgr_RecalcWarpImageSize (void); void R_ClearTextureChains (qmodel_t *mod, texchain_t chain); void R_ChainSurface (msurface_t *surf, texchain_t chain); void R_DrawTextureChains (qmodel_t *model, entity_t *ent, texchain_t chain); void R_DrawWorld_Water (void); void GL_BindBuffer (GLenum target, GLuint buffer); void GL_ClearBufferBindings (); void GLSLGamma_DeleteTexture (void); void GLSLGamma_GammaCorrect (void); float GL_WaterAlphaForSurface (msurface_t *fa); #endif /* __GLQUAKE_H */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/strlcat.c�������������������������������������������������������������������0000644�0000000�0000000�00000003256�11676323013�015347� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ /* * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/types.h> #include <string.h> #include "strl_fn.h" /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t q_strlcat (char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_main.c������������������������������������������������������������������0000644�0000000�0000000�00000041450�12506735242�015467� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "q_stdinc.h" #include "arch_def.h" #include "net_sys.h" #include "quakedef.h" #include "net_defs.h" qsocket_t *net_activeSockets = NULL; qsocket_t *net_freeSockets = NULL; int net_numsockets = 0; qboolean ipxAvailable = false; qboolean tcpipAvailable = false; int net_hostport; int DEFAULTnet_hostport = 26000; char my_ipx_address[NET_NAMELEN]; char my_tcpip_address[NET_NAMELEN]; static qboolean listening = false; qboolean slistInProgress = false; qboolean slistSilent = false; qboolean slistLocal = true; static double slistStartTime; static int slistLastShown; static void Slist_Send (void *); static void Slist_Poll (void *); static PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send}; static PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll}; sizebuf_t net_message; int net_activeconnections = 0; int messagesSent = 0; int messagesReceived = 0; int unreliableMessagesSent = 0; int unreliableMessagesReceived = 0; static cvar_t net_messagetimeout = {"net_messagetimeout","300",CVAR_NONE}; cvar_t hostname = {"hostname", "UNNAMED", CVAR_NONE}; // these two macros are to make the code more readable #define sfunc net_drivers[sock->driver] #define dfunc net_drivers[net_driverlevel] int net_driverlevel; double net_time; double SetNetTime (void) { net_time = Sys_DoubleTime(); return net_time; } /* =================== NET_NewQSocket Called by drivers when a new communications endpoint is required The sequence and buffer fields will be filled in properly =================== */ qsocket_t *NET_NewQSocket (void) { qsocket_t *sock; if (net_freeSockets == NULL) return NULL; if (net_activeconnections >= svs.maxclients) return NULL; // get one from free list sock = net_freeSockets; net_freeSockets = sock->next; // add it to active list sock->next = net_activeSockets; net_activeSockets = sock; sock->disconnected = false; sock->connecttime = net_time; Q_strcpy (sock->address,"UNSET ADDRESS"); sock->driver = net_driverlevel; sock->socket = 0; sock->driverdata = NULL; sock->canSend = true; sock->sendNext = false; sock->lastMessageTime = net_time; sock->ackSequence = 0; sock->sendSequence = 0; sock->unreliableSendSequence = 0; sock->sendMessageLength = 0; sock->receiveSequence = 0; sock->unreliableReceiveSequence = 0; sock->receiveMessageLength = 0; return sock; } void NET_FreeQSocket(qsocket_t *sock) { qsocket_t *s; // remove it from active list if (sock == net_activeSockets) net_activeSockets = net_activeSockets->next; else { for (s = net_activeSockets; s; s = s->next) { if (s->next == sock) { s->next = sock->next; break; } } if (!s) Sys_Error ("NET_FreeQSocket: not active"); } // add it to free list sock->next = net_freeSockets; net_freeSockets = sock; sock->disconnected = true; } double NET_QSocketGetTime (const qsocket_t *s) { return s->connecttime; } const char *NET_QSocketGetAddressString (const qsocket_t *s) { return s->address; } static void NET_Listen_f (void) { if (Cmd_Argc () != 2) { Con_Printf ("\"listen\" is \"%d\"\n", listening ? 1 : 0); return; } listening = Q_atoi(Cmd_Argv(1)) ? true : false; for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) { if (net_drivers[net_driverlevel].initialized == false) continue; dfunc.Listen (listening); } } static void MaxPlayers_f (void) { int n; if (Cmd_Argc () != 2) { Con_Printf ("\"maxplayers\" is \"%d\"\n", svs.maxclients); return; } if (sv.active) { Con_Printf ("maxplayers can not be changed while a server is running.\n"); return; } n = Q_atoi(Cmd_Argv(1)); if (n < 1) n = 1; if (n > svs.maxclientslimit) { n = svs.maxclientslimit; Con_Printf ("\"maxplayers\" set to \"%d\"\n", n); } if ((n == 1) && listening) Cbuf_AddText ("listen 0\n"); if ((n > 1) && (!listening)) Cbuf_AddText ("listen 1\n"); svs.maxclients = n; if (n == 1) Cvar_Set ("deathmatch", "0"); else Cvar_Set ("deathmatch", "1"); } static void NET_Port_f (void) { int n; if (Cmd_Argc () != 2) { Con_Printf ("\"port\" is \"%d\"\n", net_hostport); return; } n = Q_atoi(Cmd_Argv(1)); if (n < 1 || n > 65534) { Con_Printf ("Bad value, must be between 1 and 65534\n"); return; } DEFAULTnet_hostport = n; net_hostport = n; if (listening) { // force a change to the new port Cbuf_AddText ("listen 0\n"); Cbuf_AddText ("listen 1\n"); } } static void PrintSlistHeader(void) { Con_Printf("Server Map Users\n"); Con_Printf("--------------- --------------- -----\n"); slistLastShown = 0; } static void PrintSlist(void) { int n; for (n = slistLastShown; n < hostCacheCount; n++) { if (hostcache[n].maxusers) Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers); else Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map); } slistLastShown = n; } static void PrintSlistTrailer(void) { if (hostCacheCount) Con_Printf("== end list ==\n\n"); else Con_Printf("No Quake servers found.\n\n"); } void NET_Slist_f (void) { if (slistInProgress) return; if (! slistSilent) { Con_Printf("Looking for Quake servers...\n"); PrintSlistHeader(); } slistInProgress = true; slistStartTime = Sys_DoubleTime(); SchedulePollProcedure(&slistSendProcedure, 0.0); SchedulePollProcedure(&slistPollProcedure, 0.1); hostCacheCount = 0; } void NET_SlistSort (void) { if (hostCacheCount > 1) { int i, j; hostcache_t temp; for (i = 0; i < hostCacheCount; i++) { for (j = i + 1; j < hostCacheCount; j++) { if (strcmp(hostcache[j].name, hostcache[i].name) < 0) { memcpy(&temp, &hostcache[j], sizeof(hostcache_t)); memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t)); memcpy(&hostcache[i], &temp, sizeof(hostcache_t)); } } } } } const char *NET_SlistPrintServer (int idx) { static char string[64]; if (idx < 0 || idx >= hostCacheCount) return ""; if (hostcache[idx].maxusers) { q_snprintf(string, sizeof(string), "%-15.15s %-15.15s %2u/%2u\n", hostcache[idx].name, hostcache[idx].map, hostcache[idx].users, hostcache[idx].maxusers); } else { q_snprintf(string, sizeof(string), "%-15.15s %-15.15s\n", hostcache[idx].name, hostcache[idx].map); } return string; } const char *NET_SlistPrintServerName (int idx) { if (idx < 0 || idx >= hostCacheCount) return ""; return hostcache[idx].cname; } static void Slist_Send (void *unused) { for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) { if (!slistLocal && IS_LOOP_DRIVER(net_driverlevel)) continue; if (net_drivers[net_driverlevel].initialized == false) continue; dfunc.SearchForHosts (true); } if ((Sys_DoubleTime() - slistStartTime) < 0.5) SchedulePollProcedure(&slistSendProcedure, 0.75); } static void Slist_Poll (void *unused) { for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) { if (!slistLocal && IS_LOOP_DRIVER(net_driverlevel)) continue; if (net_drivers[net_driverlevel].initialized == false) continue; dfunc.SearchForHosts (false); } if (! slistSilent) PrintSlist(); if ((Sys_DoubleTime() - slistStartTime) < 1.5) { SchedulePollProcedure(&slistPollProcedure, 0.1); return; } if (! slistSilent) PrintSlistTrailer(); slistInProgress = false; slistSilent = false; slistLocal = true; } /* =================== NET_Connect =================== */ int hostCacheCount = 0; hostcache_t hostcache[HOSTCACHESIZE]; qsocket_t *NET_Connect (const char *host) { qsocket_t *ret; int n; int numdrivers = net_numdrivers; SetNetTime(); if (host && *host == 0) host = NULL; if (host) { if (q_strcasecmp (host, "local") == 0) { numdrivers = 1; goto JustDoIt; } if (hostCacheCount) { for (n = 0; n < hostCacheCount; n++) if (q_strcasecmp (host, hostcache[n].name) == 0) { host = hostcache[n].cname; break; } if (n < hostCacheCount) goto JustDoIt; } } slistSilent = host ? true : false; NET_Slist_f (); while (slistInProgress) NET_Poll(); if (host == NULL) { if (hostCacheCount != 1) return NULL; host = hostcache[0].cname; Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host); } if (hostCacheCount) { for (n = 0; n < hostCacheCount; n++) { if (q_strcasecmp (host, hostcache[n].name) == 0) { host = hostcache[n].cname; break; } } } JustDoIt: for (net_driverlevel = 0; net_driverlevel < numdrivers; net_driverlevel++) { if (net_drivers[net_driverlevel].initialized == false) continue; ret = dfunc.Connect (host); if (ret) return ret; } if (host) { Con_Printf("\n"); PrintSlistHeader(); PrintSlist(); PrintSlistTrailer(); } return NULL; } /* =================== NET_CheckNewConnections =================== */ qsocket_t *NET_CheckNewConnections (void) { qsocket_t *ret; SetNetTime(); for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) { if (net_drivers[net_driverlevel].initialized == false) continue; if (!IS_LOOP_DRIVER(net_driverlevel) && listening == false) continue; ret = dfunc.CheckNewConnections (); if (ret) { return ret; } } return NULL; } /* =================== NET_Close =================== */ void NET_Close (qsocket_t *sock) { if (!sock) return; if (sock->disconnected) return; SetNetTime(); // call the driver_Close function sfunc.Close (sock); NET_FreeQSocket(sock); } /* ================= NET_GetMessage If there is a complete message, return it in net_message returns 0 if no data is waiting returns 1 if a message was received returns -1 if connection is invalid ================= */ int NET_GetMessage (qsocket_t *sock) { int ret; if (!sock) return -1; if (sock->disconnected) { Con_Printf("NET_GetMessage: disconnected socket\n"); return -1; } SetNetTime(); ret = sfunc.QGetMessage(sock); // see if this connection has timed out if (ret == 0 && !IS_LOOP_DRIVER(sock->driver)) { if (net_time - sock->lastMessageTime > net_messagetimeout.value) { NET_Close(sock); return -1; } } if (ret > 0) { if (!IS_LOOP_DRIVER(sock->driver)) { sock->lastMessageTime = net_time; if (ret == 1) messagesReceived++; else if (ret == 2) unreliableMessagesReceived++; } } return ret; } /* ================== NET_SendMessage Try to send a complete length+message unit over the reliable stream. returns 0 if the message cannot be delivered reliably, but the connection is still considered valid returns 1 if the message was sent properly returns -1 if the connection died ================== */ int NET_SendMessage (qsocket_t *sock, sizebuf_t *data) { int r; if (!sock) return -1; if (sock->disconnected) { Con_Printf("NET_SendMessage: disconnected socket\n"); return -1; } SetNetTime(); r = sfunc.QSendMessage(sock, data); if (r == 1 && !IS_LOOP_DRIVER(sock->driver)) messagesSent++; return r; } int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) { int r; if (!sock) return -1; if (sock->disconnected) { Con_Printf("NET_SendMessage: disconnected socket\n"); return -1; } SetNetTime(); r = sfunc.SendUnreliableMessage(sock, data); if (r == 1 && !IS_LOOP_DRIVER(sock->driver)) unreliableMessagesSent++; return r; } /* ================== NET_CanSendMessage Returns true or false if the given qsocket can currently accept a message to be transmitted. ================== */ qboolean NET_CanSendMessage (qsocket_t *sock) { if (!sock) return false; if (sock->disconnected) return false; SetNetTime(); return sfunc.CanSendMessage(sock); } int NET_SendToAll (sizebuf_t *data, double blocktime) { double start; int i; int count = 0; qboolean msg_init[MAX_SCOREBOARD]; /* did we write the message to the client's connection */ qboolean msg_sent[MAX_SCOREBOARD]; /* did the msg arrive its destination (canSend state). */ for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) { /* if (!host_client->netconnection) continue; if (host_client->active) */ if (host_client->netconnection && host_client->active) { if (IS_LOOP_DRIVER(host_client->netconnection->driver)) { NET_SendMessage(host_client->netconnection, data); msg_init[i] = true; msg_sent[i] = true; continue; } count++; msg_init[i] = false; msg_sent[i] = false; } else { msg_init[i] = true; msg_sent[i] = true; } } start = Sys_DoubleTime(); while (count) { count = 0; for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) { if (! msg_init[i]) { if (NET_CanSendMessage (host_client->netconnection)) { msg_init[i] = true; NET_SendMessage(host_client->netconnection, data); } else { NET_GetMessage (host_client->netconnection); } count++; continue; } if (! msg_sent[i]) { if (NET_CanSendMessage (host_client->netconnection)) { msg_sent[i] = true; } else { NET_GetMessage (host_client->netconnection); } count++; continue; } } if ((Sys_DoubleTime() - start) > blocktime) break; } return count; } //============================================================================= /* ==================== NET_Init ==================== */ void NET_Init (void) { int i; qsocket_t *s; i = COM_CheckParm ("-port"); if (!i) i = COM_CheckParm ("-udpport"); if (!i) i = COM_CheckParm ("-ipxport"); if (i) { if (i < com_argc-1) DEFAULTnet_hostport = Q_atoi (com_argv[i+1]); else Sys_Error ("NET_Init: you must specify a number after -port"); } net_hostport = DEFAULTnet_hostport; net_numsockets = svs.maxclientslimit; if (cls.state != ca_dedicated) net_numsockets++; if (COM_CheckParm("-listen") || cls.state == ca_dedicated) listening = true; SetNetTime(); for (i = 0; i < net_numsockets; i++) { s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket"); s->next = net_freeSockets; net_freeSockets = s; s->disconnected = true; } // allocate space for network message buffer SZ_Alloc (&net_message, NET_MAXMESSAGE); Cvar_RegisterVariable (&net_messagetimeout); Cvar_RegisterVariable (&hostname); Cmd_AddCommand ("slist", NET_Slist_f); Cmd_AddCommand ("listen", NET_Listen_f); Cmd_AddCommand ("maxplayers", MaxPlayers_f); Cmd_AddCommand ("port", NET_Port_f); // initialize all the drivers for (i = net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) { if (net_drivers[net_driverlevel].Init() == -1) continue; i++; net_drivers[net_driverlevel].initialized = true; if (listening) net_drivers[net_driverlevel].Listen (true); } /* Loop_Init() returns -1 for dedicated server case, * therefore the i == 0 check is correct */ if (i == 0 && cls.state == ca_dedicated ) { Sys_Error("Network not available!"); } if (*my_ipx_address) { Con_DPrintf("IPX address %s\n", my_ipx_address); } if (*my_tcpip_address) { Con_DPrintf("TCP/IP address %s\n", my_tcpip_address); } } /* ==================== NET_Shutdown ==================== */ void NET_Shutdown (void) { qsocket_t *sock; SetNetTime(); for (sock = net_activeSockets; sock; sock = sock->next) NET_Close(sock); // // shutdown the drivers // for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) { if (net_drivers[net_driverlevel].initialized == true) { net_drivers[net_driverlevel].Shutdown (); net_drivers[net_driverlevel].initialized = false; } } } static PollProcedure *pollProcedureList = NULL; void NET_Poll(void) { PollProcedure *pp; SetNetTime(); for (pp = pollProcedureList; pp; pp = pp->next) { if (pp->nextTime > net_time) break; pollProcedureList = pp->next; pp->procedure(pp->arg); } } void SchedulePollProcedure(PollProcedure *proc, double timeOffset) { PollProcedure *pp, *prev; proc->nextTime = Sys_DoubleTime() + timeOffset; for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next) { if (pp->nextTime >= proc->nextTime) break; prev = pp; } if (prev == NULL) { proc->next = pollProcedureList; pollProcedureList = proc; return; } proc->next = pp; prev->next = proc; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/view.c����������������������������������������������������������������������0000644�0000000�0000000�00000052321�12407762022�014642� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // view.c -- player eye positioning #include "quakedef.h" /* The view is allowed to move slightly from it's true position for bobbing, but if it exceeds 8 pixels linear distance (spherical, not box), the list of entities sent from the server may not include everything in the pvs, especially when crossing a water boudnary. */ cvar_t scr_ofsx = {"scr_ofsx","0", CVAR_NONE}; cvar_t scr_ofsy = {"scr_ofsy","0", CVAR_NONE}; cvar_t scr_ofsz = {"scr_ofsz","0", CVAR_NONE}; cvar_t cl_rollspeed = {"cl_rollspeed", "200", CVAR_NONE}; cvar_t cl_rollangle = {"cl_rollangle", "2.0", CVAR_NONE}; cvar_t cl_bob = {"cl_bob","0.02", CVAR_NONE}; cvar_t cl_bobcycle = {"cl_bobcycle","0.6", CVAR_NONE}; cvar_t cl_bobup = {"cl_bobup","0.5", CVAR_NONE}; cvar_t v_kicktime = {"v_kicktime", "0.5", CVAR_NONE}; cvar_t v_kickroll = {"v_kickroll", "0.6", CVAR_NONE}; cvar_t v_kickpitch = {"v_kickpitch", "0.6", CVAR_NONE}; cvar_t v_gunkick = {"v_gunkick", "1", CVAR_NONE}; //johnfitz cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", CVAR_NONE}; cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", CVAR_NONE}; cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", CVAR_NONE}; cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", CVAR_NONE}; cvar_t v_iroll_level = {"v_iroll_level", "0.1", CVAR_NONE}; cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", CVAR_NONE}; cvar_t v_idlescale = {"v_idlescale", "0", CVAR_NONE}; cvar_t crosshair = {"crosshair", "0", CVAR_ARCHIVE}; cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", CVAR_NONE}; float v_dmg_time, v_dmg_roll, v_dmg_pitch; extern int in_forward, in_forward2, in_back; vec3_t v_punchangles[2]; //johnfitz -- copied from cl.punchangle. 0 is current, 1 is previous value. never the same unless map just loaded /* =============== V_CalcRoll Used by view and sv_user =============== */ float V_CalcRoll (vec3_t angles, vec3_t velocity) { vec3_t forward, right, up; float sign; float side; float value; AngleVectors (angles, forward, right, up); side = DotProduct (velocity, right); sign = side < 0 ? -1 : 1; side = fabs(side); value = cl_rollangle.value; // if (cl.inwater) // value *= 6; if (side < cl_rollspeed.value) side = side * value / cl_rollspeed.value; else side = value; return side*sign; } /* =============== V_CalcBob =============== */ float V_CalcBob (void) { float bob; float cycle; cycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value; cycle /= cl_bobcycle.value; if (cycle < cl_bobup.value) cycle = M_PI * cycle / cl_bobup.value; else cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value); // bob is proportional to velocity in the xy plane // (don't count Z, or jumping messes it up) bob = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value; //Con_Printf ("speed: %5.1f\n", VectorLength(cl.velocity)); bob = bob*0.3 + bob*0.7*sin(cycle); if (bob > 4) bob = 4; else if (bob < -7) bob = -7; return bob; } //============================================================================= cvar_t v_centermove = {"v_centermove", "0.15", CVAR_NONE}; cvar_t v_centerspeed = {"v_centerspeed","500", CVAR_NONE}; void V_StartPitchDrift (void) { #if 1 if (cl.laststop == cl.time) { return; // something else is keeping it from drifting } #endif if (cl.nodrift || !cl.pitchvel) { cl.pitchvel = v_centerspeed.value; cl.nodrift = false; cl.driftmove = 0; } } void V_StopPitchDrift (void) { cl.laststop = cl.time; cl.nodrift = true; cl.pitchvel = 0; } /* =============== V_DriftPitch Moves the client pitch angle towards cl.idealpitch sent by the server. If the user is adjusting pitch manually, either with lookup/lookdown, mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. Drifting is enabled when the center view key is hit, mlook is released and lookspring is non 0, or when =============== */ void V_DriftPitch (void) { float delta, move; if (noclip_anglehack || !cl.onground || cls.demoplayback ) //FIXME: noclip_anglehack is set on the server, so in a nonlocal game this won't work. { cl.driftmove = 0; cl.pitchvel = 0; return; } // don't count small mouse motion if (cl.nodrift) { if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value) cl.driftmove = 0; else cl.driftmove += host_frametime; if ( cl.driftmove > v_centermove.value) { if (lookspring.value) V_StartPitchDrift (); } return; } delta = cl.idealpitch - cl.viewangles[PITCH]; if (!delta) { cl.pitchvel = 0; return; } move = host_frametime * cl.pitchvel; cl.pitchvel += host_frametime * v_centerspeed.value; //Con_Printf ("move: %f (%f)\n", move, host_frametime); if (delta > 0) { if (move > delta) { cl.pitchvel = 0; move = delta; } cl.viewangles[PITCH] += move; } else if (delta < 0) { if (move > -delta) { cl.pitchvel = 0; move = -delta; } cl.viewangles[PITCH] -= move; } } /* ============================================================================== VIEW BLENDING ============================================================================== */ cshift_t cshift_empty = { {130,80,50}, 0 }; cshift_t cshift_water = { {130,80,50}, 128 }; cshift_t cshift_slime = { {0,25,5}, 150 }; cshift_t cshift_lava = { {255,80,0}, 150 }; float v_blend[4]; // rgba 0.0 - 1.0 //johnfitz -- deleted BuildGammaTable(), V_CheckGamma(), gammatable[], and ramps[][] /* =============== V_ParseDamage =============== */ void V_ParseDamage (void) { int armor, blood; vec3_t from; int i; vec3_t forward, right, up; entity_t *ent; float side; float count; armor = MSG_ReadByte (); blood = MSG_ReadByte (); for (i=0 ; i<3 ; i++) from[i] = MSG_ReadCoord (); count = blood*0.5 + armor*0.5; if (count < 10) count = 10; cl.faceanimtime = cl.time + 0.2; // but sbar face into pain frame cl.cshifts[CSHIFT_DAMAGE].percent += 3*count; if (cl.cshifts[CSHIFT_DAMAGE].percent < 0) cl.cshifts[CSHIFT_DAMAGE].percent = 0; if (cl.cshifts[CSHIFT_DAMAGE].percent > 150) cl.cshifts[CSHIFT_DAMAGE].percent = 150; if (armor > blood) { cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; } else if (armor) { cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; } else { cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255; cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; } // // calculate view angle kicks // ent = &cl_entities[cl.viewentity]; VectorSubtract (from, ent->origin, from); VectorNormalize (from); AngleVectors (ent->angles, forward, right, up); side = DotProduct (from, right); v_dmg_roll = count*side*v_kickroll.value; side = DotProduct (from, forward); v_dmg_pitch = count*side*v_kickpitch.value; v_dmg_time = v_kicktime.value; } /* ================== V_cshift_f ================== */ void V_cshift_f (void) { cshift_empty.destcolor[0] = atoi(Cmd_Argv(1)); cshift_empty.destcolor[1] = atoi(Cmd_Argv(2)); cshift_empty.destcolor[2] = atoi(Cmd_Argv(3)); cshift_empty.percent = atoi(Cmd_Argv(4)); } /* ================== V_BonusFlash_f When you run over an item, the server sends this command ================== */ void V_BonusFlash_f (void) { cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215; cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186; cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69; cl.cshifts[CSHIFT_BONUS].percent = 50; } /* ============= V_SetContentsColor Underwater, lava, etc each has a color shift ============= */ void V_SetContentsColor (int contents) { switch (contents) { case CONTENTS_EMPTY: case CONTENTS_SOLID: case CONTENTS_SKY: //johnfitz -- no blend in sky cl.cshifts[CSHIFT_CONTENTS] = cshift_empty; break; case CONTENTS_LAVA: cl.cshifts[CSHIFT_CONTENTS] = cshift_lava; break; case CONTENTS_SLIME: cl.cshifts[CSHIFT_CONTENTS] = cshift_slime; break; default: cl.cshifts[CSHIFT_CONTENTS] = cshift_water; } } /* ============= V_CalcPowerupCshift ============= */ void V_CalcPowerupCshift (void) { if (cl.items & IT_QUAD) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255; cl.cshifts[CSHIFT_POWERUP].percent = 30; } else if (cl.items & IT_SUIT) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; cl.cshifts[CSHIFT_POWERUP].percent = 20; } else if (cl.items & IT_INVISIBILITY) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100; cl.cshifts[CSHIFT_POWERUP].percent = 100; } else if (cl.items & IT_INVULNERABILITY) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; cl.cshifts[CSHIFT_POWERUP].percent = 30; } else cl.cshifts[CSHIFT_POWERUP].percent = 0; } /* ============= V_CalcBlend ============= */ void V_CalcBlend (void) { float r, g, b, a, a2; int j; r = 0; g = 0; b = 0; a = 0; for (j=0 ; j<NUM_CSHIFTS ; j++) { if (!gl_cshiftpercent.value) continue; //johnfitz -- only apply leaf contents color shifts during intermission if (cl.intermission && j != CSHIFT_CONTENTS) continue; //johnfitz a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0; if (!a2) continue; a = a + a2*(1-a); a2 = a2/a; r = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2; g = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2; b = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2; } v_blend[0] = r/255.0; v_blend[1] = g/255.0; v_blend[2] = b/255.0; v_blend[3] = a; if (v_blend[3] > 1) v_blend[3] = 1; if (v_blend[3] < 0) v_blend[3] = 0; } /* ============= V_UpdateBlend -- johnfitz -- V_UpdatePalette cleaned up and renamed ============= */ void V_UpdateBlend (void) { int i, j; qboolean blend_changed; V_CalcPowerupCshift (); blend_changed = false; for (i=0 ; i<NUM_CSHIFTS ; i++) { if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent) { blend_changed = true; cl.prev_cshifts[i].percent = cl.cshifts[i].percent; } for (j=0 ; j<3 ; j++) if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j]) { blend_changed = true; cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j]; } } // drop the damage value cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150; if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0) cl.cshifts[CSHIFT_DAMAGE].percent = 0; // drop the bonus value cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100; if (cl.cshifts[CSHIFT_BONUS].percent <= 0) cl.cshifts[CSHIFT_BONUS].percent = 0; if (blend_changed) V_CalcBlend (); } /* ============ V_PolyBlend -- johnfitz -- moved here from gl_rmain.c, and rewritten to use glOrtho ============ */ void V_PolyBlend (void) { if (!gl_polyblend.value || !v_blend[3]) return; GL_DisableMultitexture(); glDisable (GL_ALPHA_TEST); glDisable (GL_TEXTURE_2D); glDisable (GL_DEPTH_TEST); glEnable (GL_BLEND); glMatrixMode(GL_PROJECTION); glLoadIdentity (); glOrtho (0, 1, 1, 0, -99999, 99999); glMatrixMode(GL_MODELVIEW); glLoadIdentity (); glColor4fv (v_blend); glBegin (GL_QUADS); glVertex2f (0,0); glVertex2f (1, 0); glVertex2f (1, 1); glVertex2f (0, 1); glEnd (); glDisable (GL_BLEND); glEnable (GL_DEPTH_TEST); glEnable (GL_TEXTURE_2D); glEnable (GL_ALPHA_TEST); } /* ============================================================================== VIEW RENDERING ============================================================================== */ float angledelta (float a) { a = anglemod(a); if (a > 180) a -= 360; return a; } /* ================== CalcGunAngle ================== */ void CalcGunAngle (void) { float yaw, pitch, move; static float oldyaw = 0; static float oldpitch = 0; yaw = r_refdef.viewangles[YAW]; pitch = -r_refdef.viewangles[PITCH]; yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4; if (yaw > 10) yaw = 10; if (yaw < -10) yaw = -10; pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4; if (pitch > 10) pitch = 10; if (pitch < -10) pitch = -10; move = host_frametime*20; if (yaw > oldyaw) { if (oldyaw + move < yaw) yaw = oldyaw + move; } else { if (oldyaw - move > yaw) yaw = oldyaw - move; } if (pitch > oldpitch) { if (oldpitch + move < pitch) pitch = oldpitch + move; } else { if (oldpitch - move > pitch) pitch = oldpitch - move; } oldyaw = yaw; oldpitch = pitch; cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw; cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch); cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; } /* ============== V_BoundOffsets ============== */ void V_BoundOffsets (void) { entity_t *ent; ent = &cl_entities[cl.viewentity]; // absolutely bound refresh reletive to entity clipping hull // so the view can never be inside a solid wall if (r_refdef.vieworg[0] < ent->origin[0] - 14) r_refdef.vieworg[0] = ent->origin[0] - 14; else if (r_refdef.vieworg[0] > ent->origin[0] + 14) r_refdef.vieworg[0] = ent->origin[0] + 14; if (r_refdef.vieworg[1] < ent->origin[1] - 14) r_refdef.vieworg[1] = ent->origin[1] - 14; else if (r_refdef.vieworg[1] > ent->origin[1] + 14) r_refdef.vieworg[1] = ent->origin[1] + 14; if (r_refdef.vieworg[2] < ent->origin[2] - 22) r_refdef.vieworg[2] = ent->origin[2] - 22; else if (r_refdef.vieworg[2] > ent->origin[2] + 30) r_refdef.vieworg[2] = ent->origin[2] + 30; } /* ============== V_AddIdle Idle swaying ============== */ void V_AddIdle (void) { r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; } /* ============== V_CalcViewRoll Roll is induced by movement and damage ============== */ void V_CalcViewRoll (void) { float side; side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity); r_refdef.viewangles[ROLL] += side; if (v_dmg_time > 0) { r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll; r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch; v_dmg_time -= host_frametime; } if (cl.stats[STAT_HEALTH] <= 0) { r_refdef.viewangles[ROLL] = 80; // dead view angle return; } } /* ================== V_CalcIntermissionRefdef ================== */ void V_CalcIntermissionRefdef (void) { entity_t *ent, *view; float old; // ent is the player model (visible when out of body) ent = &cl_entities[cl.viewentity]; // view is the weapon model (only visible from inside body) view = &cl.viewent; VectorCopy (ent->origin, r_refdef.vieworg); VectorCopy (ent->angles, r_refdef.viewangles); view->model = NULL; // allways idle in intermission old = v_idlescale.value; v_idlescale.value = 1; V_AddIdle (); v_idlescale.value = old; } /* ================== V_CalcRefdef ================== */ void V_CalcRefdef (void) { entity_t *ent, *view; int i; vec3_t forward, right, up; vec3_t angles; float bob; static float oldz = 0; static vec3_t punch = {0,0,0}; //johnfitz -- v_gunkick float delta; //johnfitz -- v_gunkick V_DriftPitch (); // ent is the player model (visible when out of body) ent = &cl_entities[cl.viewentity]; // view is the weapon model (only visible from inside body) view = &cl.viewent; // transform the view offset by the model's matrix to get the offset from // model origin for the view ent->angles[YAW] = cl.viewangles[YAW]; // the model should face the view dir ent->angles[PITCH] = -cl.viewangles[PITCH]; // the model should face the view dir bob = V_CalcBob (); // refresh position VectorCopy (ent->origin, r_refdef.vieworg); r_refdef.vieworg[2] += cl.viewheight + bob; // never let it sit exactly on a node line, because a water plane can // dissapear when viewed with the eye exactly on it. // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis r_refdef.vieworg[0] += 1.0/32; r_refdef.vieworg[1] += 1.0/32; r_refdef.vieworg[2] += 1.0/32; VectorCopy (cl.viewangles, r_refdef.viewangles); V_CalcViewRoll (); V_AddIdle (); // offsets angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are actually backward angles[YAW] = ent->angles[YAW]; angles[ROLL] = ent->angles[ROLL]; AngleVectors (angles, forward, right, up); if (cl.maxclients <= 1) //johnfitz -- moved cheat-protection here from V_RenderView for (i=0 ; i<3 ; i++) r_refdef.vieworg[i] += scr_ofsx.value*forward[i] + scr_ofsy.value*right[i] + scr_ofsz.value*up[i]; V_BoundOffsets (); // set up gun position VectorCopy (cl.viewangles, view->angles); CalcGunAngle (); VectorCopy (ent->origin, view->origin); view->origin[2] += cl.viewheight; for (i=0 ; i<3 ; i++) view->origin[i] += forward[i]*bob*0.4; view->origin[2] += bob; //johnfitz -- removed all gun position fudging code (was used to keep gun from getting covered by sbar) view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; view->frame = cl.stats[STAT_WEAPONFRAME]; view->colormap = vid.colormap; //johnfitz -- v_gunkick if (v_gunkick.value == 1) //original quake kick VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles); if (v_gunkick.value == 2) //lerped kick { for (i=0; i<3; i++) if (punch[i] != v_punchangles[0][i]) { //speed determined by how far we need to lerp in 1/10th of a second delta = (v_punchangles[0][i]-v_punchangles[1][i]) * host_frametime * 10; if (delta > 0) punch[i] = q_min(punch[i]+delta, v_punchangles[0][i]); else if (delta < 0) punch[i] = q_max(punch[i]+delta, v_punchangles[0][i]); } VectorAdd (r_refdef.viewangles, punch, r_refdef.viewangles); } //johnfitz // smooth out stair step ups if (!noclip_anglehack && cl.onground && ent->origin[2] - oldz > 0) //johnfitz -- added exception for noclip //FIXME: noclip_anglehack is set on the server, so in a nonlocal game this won't work. { float steptime; steptime = cl.time - cl.oldtime; if (steptime < 0) //FIXME I_Error ("steptime < 0"); steptime = 0; oldz += steptime * 80; if (oldz > ent->origin[2]) oldz = ent->origin[2]; if (ent->origin[2] - oldz > 12) oldz = ent->origin[2] - 12; r_refdef.vieworg[2] += oldz - ent->origin[2]; view->origin[2] += oldz - ent->origin[2]; } else oldz = ent->origin[2]; if (chase_active.value) Chase_UpdateForDrawing (); //johnfitz } /* ================== V_RenderView The player's clipping box goes from (-16 -16 -24) to (16 16 32) from the entity origin, so any view position inside that will be valid ================== */ extern vrect_t scr_vrect; void V_RenderView (void) { if (con_forcedup) return; if (cl.intermission) V_CalcIntermissionRefdef (); else if (!cl.paused /* && (cl.maxclients > 1 || key_dest == key_game) */) V_CalcRefdef (); //johnfitz -- removed lcd code R_RenderView (); V_PolyBlend (); //johnfitz -- moved here from R_Renderview (); } /* ============================================================================== INIT ============================================================================== */ /* ============= V_Init ============= */ void V_Init (void) { Cmd_AddCommand ("v_cshift", V_cshift_f); Cmd_AddCommand ("bf", V_BonusFlash_f); Cmd_AddCommand ("centerview", V_StartPitchDrift); Cvar_RegisterVariable (&v_centermove); Cvar_RegisterVariable (&v_centerspeed); Cvar_RegisterVariable (&v_iyaw_cycle); Cvar_RegisterVariable (&v_iroll_cycle); Cvar_RegisterVariable (&v_ipitch_cycle); Cvar_RegisterVariable (&v_iyaw_level); Cvar_RegisterVariable (&v_iroll_level); Cvar_RegisterVariable (&v_ipitch_level); Cvar_RegisterVariable (&v_idlescale); Cvar_RegisterVariable (&crosshair); Cvar_RegisterVariable (&gl_cshiftpercent); Cvar_RegisterVariable (&scr_ofsx); Cvar_RegisterVariable (&scr_ofsy); Cvar_RegisterVariable (&scr_ofsz); Cvar_RegisterVariable (&cl_rollspeed); Cvar_RegisterVariable (&cl_rollangle); Cvar_RegisterVariable (&cl_bob); Cvar_RegisterVariable (&cl_bobcycle); Cvar_RegisterVariable (&cl_bobup); Cvar_RegisterVariable (&v_kicktime); Cvar_RegisterVariable (&v_kickroll); Cvar_RegisterVariable (&v_kickpitch); Cvar_RegisterVariable (&v_gunkick); //johnfitz } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_rlight.c�����������������������������������������������������������������0000644�0000000�0000000�00000024637�12461361335�015656� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // r_light.c #include "quakedef.h" int r_dlightframecount; extern cvar_t r_flatlightstyles; //johnfitz /* ================== R_AnimateLight ================== */ void R_AnimateLight (void) { int i,j,k; // // light animations // 'm' is normal light, 'a' is no light, 'z' is double bright i = (int)(cl.time*10); for (j=0 ; j<MAX_LIGHTSTYLES ; j++) { if (!cl_lightstyle[j].length) { d_lightstylevalue[j] = 256; continue; } //johnfitz -- r_flatlightstyles if (r_flatlightstyles.value == 2) k = cl_lightstyle[j].peak - 'a'; else if (r_flatlightstyles.value == 1) k = cl_lightstyle[j].average - 'a'; else { k = i % cl_lightstyle[j].length; k = cl_lightstyle[j].map[k] - 'a'; } d_lightstylevalue[j] = k*22; //johnfitz } } /* ============================================================================= DYNAMIC LIGHTS BLEND RENDERING (gl_flashblend 1) ============================================================================= */ void AddLightBlend (float r, float g, float b, float a2) { float a; v_blend[3] = a = v_blend[3] + a2*(1-v_blend[3]); a2 = a2/a; v_blend[0] = v_blend[1]*(1-a2) + r*a2; v_blend[1] = v_blend[1]*(1-a2) + g*a2; v_blend[2] = v_blend[2]*(1-a2) + b*a2; } void R_RenderDlight (dlight_t *light) { int i, j; float a; vec3_t v; float rad; rad = light->radius * 0.35; VectorSubtract (light->origin, r_origin, v); if (VectorLength (v) < rad) { // view is inside the dlight AddLightBlend (1, 0.5, 0, light->radius * 0.0003); return; } glBegin (GL_TRIANGLE_FAN); glColor3f (0.2,0.1,0.0); for (i=0 ; i<3 ; i++) v[i] = light->origin[i] - vpn[i]*rad; glVertex3fv (v); glColor3f (0,0,0); for (i=16 ; i>=0 ; i--) { a = i/16.0 * M_PI*2; for (j=0 ; j<3 ; j++) v[j] = light->origin[j] + vright[j]*cos(a)*rad + vup[j]*sin(a)*rad; glVertex3fv (v); } glEnd (); } /* ============= R_RenderDlights ============= */ void R_RenderDlights (void) { int i; dlight_t *l; if (!gl_flashblend.value) return; r_dlightframecount = r_framecount + 1; // because the count hasn't // advanced yet for this frame glDepthMask (0); glDisable (GL_TEXTURE_2D); glShadeModel (GL_SMOOTH); glEnable (GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); l = cl_dlights; for (i=0 ; i<MAX_DLIGHTS ; i++, l++) { if (l->die < cl.time || !l->radius) continue; R_RenderDlight (l); } glColor3f (1,1,1); glDisable (GL_BLEND); glEnable (GL_TEXTURE_2D); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask (1); } /* ============================================================================= DYNAMIC LIGHTS ============================================================================= */ /* ============= R_MarkLights -- johnfitz -- rewritten to use LordHavoc's lighting speedup ============= */ void R_MarkLights (dlight_t *light, int num, mnode_t *node) { mplane_t *splitplane; msurface_t *surf; vec3_t impact; float dist, l, maxdist; int i, j, s, t; start: if (node->contents < 0) return; splitplane = node->plane; if (splitplane->type < 3) dist = light->origin[splitplane->type] - splitplane->dist; else dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; if (dist > light->radius) { node = node->children[0]; goto start; } if (dist < -light->radius) { node = node->children[1]; goto start; } maxdist = light->radius*light->radius; // mark the polygons surf = cl.worldmodel->surfaces + node->firstsurface; for (i=0 ; i<node->numsurfaces ; i++, surf++) { for (j=0 ; j<3 ; j++) impact[j] = light->origin[j] - surf->plane->normal[j]*dist; // clamp center of light to corner and check brightness l = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0]; s = l+0.5;if (s < 0) s = 0;else if (s > surf->extents[0]) s = surf->extents[0]; s = l - s; l = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1]; t = l+0.5;if (t < 0) t = 0;else if (t > surf->extents[1]) t = surf->extents[1]; t = l - t; // compare to minimum light if ((s*s+t*t+dist*dist) < maxdist) { if (surf->dlightframe != r_dlightframecount) // not dynamic until now { surf->dlightbits[num >> 5] = 1U << (num & 31); surf->dlightframe = r_dlightframecount; } else // already dynamic surf->dlightbits[num >> 5] |= 1U << (num & 31); } } if (node->children[0]->contents >= 0) R_MarkLights (light, num, node->children[0]); if (node->children[1]->contents >= 0) R_MarkLights (light, num, node->children[1]); } /* ============= R_PushDlights ============= */ void R_PushDlights (void) { int i; dlight_t *l; if (gl_flashblend.value) return; r_dlightframecount = r_framecount + 1; // because the count hasn't // advanced yet for this frame l = cl_dlights; for (i=0 ; i<MAX_DLIGHTS ; i++, l++) { if (l->die < cl.time || !l->radius) continue; R_MarkLights (l, i, cl.worldmodel->nodes); } } /* ============================================================================= LIGHT SAMPLING ============================================================================= */ mplane_t *lightplane; vec3_t lightspot; vec3_t lightcolor; //johnfitz -- lit support via lordhavoc #define DoublePrecisionDotProduct(x,y) ((double)x[0]*y[0]+(double)x[1]*y[1]+(double)x[2]*y[2]) /* ============= RecursiveLightPoint -- johnfitz -- replaced entire function for lit support via lordhavoc ============= */ int RecursiveLightPoint (vec3_t color, mnode_t *node, vec3_t start, vec3_t end) { float front, back, frac; vec3_t mid; loc0: if (node->contents < 0) return false; // didn't hit anything // calculate mid point if (node->plane->type < 3) { front = start[node->plane->type] - node->plane->dist; back = end[node->plane->type] - node->plane->dist; } else { front = DotProduct(start, node->plane->normal) - node->plane->dist; back = DotProduct(end, node->plane->normal) - node->plane->dist; } // LordHavoc: optimized recursion if ((back < 0) == (front < 0)) // return RecursiveLightPoint (color, node->children[front < 0], start, end); { node = node->children[front < 0]; goto loc0; } frac = front / (front-back); mid[0] = start[0] + (end[0] - start[0])*frac; mid[1] = start[1] + (end[1] - start[1])*frac; mid[2] = start[2] + (end[2] - start[2])*frac; // go down front side if (RecursiveLightPoint (color, node->children[front < 0], start, mid)) return true; // hit something else { int i, ds, dt; msurface_t *surf; // check for impact on this node VectorCopy (mid, lightspot); lightplane = node->plane; surf = cl.worldmodel->surfaces + node->firstsurface; for (i = 0;i < node->numsurfaces;i++, surf++) { if (surf->flags & SURF_DRAWTILED) continue; // no lightmaps // ericw -- added double casts to force 64-bit precision. // Without them the zombie at the start of jam3_ericw.bsp was // incorrectly being lit up in SSE builds. ds = (int) ((double) DoublePrecisionDotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]); dt = (int) ((double) DoublePrecisionDotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]); if (ds < surf->texturemins[0] || dt < surf->texturemins[1]) continue; ds -= surf->texturemins[0]; dt -= surf->texturemins[1]; if (ds > surf->extents[0] || dt > surf->extents[1]) continue; if (surf->samples) { // LordHavoc: enhanced to interpolate lighting byte *lightmap; int maps, line3, dsfrac = ds & 15, dtfrac = dt & 15, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0; float scale; line3 = ((surf->extents[0]>>4)+1)*3; lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++) { scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0; r00 += (float) lightmap[ 0] * scale;g00 += (float) lightmap[ 1] * scale;b00 += (float) lightmap[2] * scale; r01 += (float) lightmap[ 3] * scale;g01 += (float) lightmap[ 4] * scale;b01 += (float) lightmap[5] * scale; r10 += (float) lightmap[line3+0] * scale;g10 += (float) lightmap[line3+1] * scale;b10 += (float) lightmap[line3+2] * scale; r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale; lightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting } color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00))); color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00))); color[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00))); } return true; // success } // go down back side return RecursiveLightPoint (color, node->children[front >= 0], mid, end); } } /* ============= R_LightPoint -- johnfitz -- replaced entire function for lit support via lordhavoc ============= */ int R_LightPoint (vec3_t p) { vec3_t end; if (!cl.worldmodel->lightdata) { lightcolor[0] = lightcolor[1] = lightcolor[2] = 255; return 255; } end[0] = p[0]; end[1] = p[1]; end[2] = p[2] - 8192; //johnfitz -- was 2048 lightcolor[0] = lightcolor[1] = lightcolor[2] = 0; RecursiveLightPoint (lightcolor, cl.worldmodel->nodes, p, end); return ((lightcolor[0] + lightcolor[1] + lightcolor[2]) * (1.0f / 3.0f)); } �������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/pl_osx.m��������������������������������������������������������������������0000644�0000000�0000000�00000004421�12407762022�015204� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif #import <Cocoa/Cocoa.h> void PL_SetWindowIcon (void) { /* nothing to do on OS X */ } void PL_VID_Shutdown (void) { } #define MAX_CLIPBOARDTXT MAXCMDLINE /* 256 */ char *PL_GetClipboardData (void) { char *data = NULL; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSArray* types = [pasteboard types]; if ([types containsObject: NSStringPboardType]) { NSString* clipboardString = [pasteboard stringForType: NSStringPboardType]; if (clipboardString != NULL && [clipboardString length] > 0) { size_t sz = [clipboardString length] + 1; sz = q_min(MAX_CLIPBOARDTXT, sz); data = (char *) Z_Malloc(sz); #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1040) /* for ppc builds targeting 10.3 and older */ q_strlcpy (data, [clipboardString cString], sz); #else q_strlcpy (data, [clipboardString cStringUsingEncoding: NSASCIIStringEncoding], sz); #endif } } return data; } void PL_ErrorDialog(const char *errorMsg) { #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1040) /* ppc builds targeting 10.3 and older */ NSString* msg = [NSString stringWithCString:errorMsg]; #else NSString* msg = [NSString stringWithCString:errorMsg encoding:NSASCIIStringEncoding]; #endif NSRunCriticalAlertPanel (@"Quake Error", msg, @"OK", nil, nil); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cl_main.c�������������������������������������������������������������������0000644�0000000�0000000�00000044737�12532130344�015301� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cl_main.c -- client main loop #include "quakedef.h" #include "bgmusic.h" // we need to declare some mouse variables here, because the menu system // references them even when on a unix system. // these two are not intended to be set directly cvar_t cl_name = {"_cl_name", "player", CVAR_ARCHIVE}; cvar_t cl_color = {"_cl_color", "0", CVAR_ARCHIVE}; cvar_t cl_shownet = {"cl_shownet","0",CVAR_NONE}; // can be 0, 1, or 2 cvar_t cl_nolerp = {"cl_nolerp","0",CVAR_NONE}; cvar_t cfg_unbindall = {"cfg_unbindall", "1", CVAR_ARCHIVE}; cvar_t lookspring = {"lookspring","0", CVAR_ARCHIVE}; cvar_t lookstrafe = {"lookstrafe","0", CVAR_ARCHIVE}; cvar_t sensitivity = {"sensitivity","3", CVAR_ARCHIVE}; cvar_t m_pitch = {"m_pitch","0.022", CVAR_ARCHIVE}; cvar_t m_yaw = {"m_yaw","0.022", CVAR_ARCHIVE}; cvar_t m_forward = {"m_forward","1", CVAR_ARCHIVE}; cvar_t m_side = {"m_side","0.8", CVAR_ARCHIVE}; cvar_t cl_maxpitch = {"cl_maxpitch", "90", CVAR_ARCHIVE}; //johnfitz -- variable pitch clamping cvar_t cl_minpitch = {"cl_minpitch", "-90", CVAR_ARCHIVE}; //johnfitz -- variable pitch clamping client_static_t cls; client_state_t cl; // FIXME: put these on hunk? efrag_t cl_efrags[MAX_EFRAGS]; entity_t cl_static_entities[MAX_STATIC_ENTITIES]; lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; dlight_t cl_dlights[MAX_DLIGHTS]; entity_t *cl_entities; //johnfitz -- was a static array, now on hunk int cl_max_edicts; //johnfitz -- only changes when new map loads int cl_numvisedicts; entity_t *cl_visedicts[MAX_VISEDICTS]; extern cvar_t r_lerpmodels, r_lerpmove; //johnfitz /* ===================== CL_ClearState ===================== */ void CL_ClearState (void) { int i; if (!sv.active) Host_ClearMemory (); // wipe the entire cl structure memset (&cl, 0, sizeof(cl)); SZ_Clear (&cls.message); // clear other arrays memset (cl_efrags, 0, sizeof(cl_efrags)); memset (cl_dlights, 0, sizeof(cl_dlights)); memset (cl_lightstyle, 0, sizeof(cl_lightstyle)); memset (cl_temp_entities, 0, sizeof(cl_temp_entities)); memset (cl_beams, 0, sizeof(cl_beams)); //johnfitz -- cl_entities is now dynamically allocated cl_max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS); cl_entities = (entity_t *) Hunk_AllocName (cl_max_edicts*sizeof(entity_t), "cl_entities"); //johnfitz // // allocate the efrags and chain together into a free list // cl.free_efrags = cl_efrags; for (i=0 ; i<MAX_EFRAGS-1 ; i++) cl.free_efrags[i].entnext = &cl.free_efrags[i+1]; cl.free_efrags[i].entnext = NULL; } /* ===================== CL_Disconnect Sends a disconnect message to the server This is also called on Host_Error, so it shouldn't cause any errors ===================== */ void CL_Disconnect (void) { if (key_dest == key_message) Key_EndChat (); // don't get stuck in chat mode // stop sounds (especially looping!) S_StopAllSounds (true); BGM_Stop(); CDAudio_Stop(); // if running a local server, shut it down if (cls.demoplayback) CL_StopPlayback (); else if (cls.state == ca_connected) { if (cls.demorecording) CL_Stop_f (); Con_DPrintf ("Sending clc_disconnect\n"); SZ_Clear (&cls.message); MSG_WriteByte (&cls.message, clc_disconnect); NET_SendUnreliableMessage (cls.netcon, &cls.message); SZ_Clear (&cls.message); NET_Close (cls.netcon); cls.state = ca_disconnected; if (sv.active) Host_ShutdownServer(false); } cls.demoplayback = cls.timedemo = false; cls.demopaused = false; cls.signon = 0; cl.intermission = 0; } void CL_Disconnect_f (void) { CL_Disconnect (); if (sv.active) Host_ShutdownServer (false); } /* ===================== CL_EstablishConnection Host should be either "local" or a net address to be passed on ===================== */ void CL_EstablishConnection (const char *host) { if (cls.state == ca_dedicated) return; if (cls.demoplayback) return; CL_Disconnect (); cls.netcon = NET_Connect (host); if (!cls.netcon) Host_Error ("CL_Connect: connect failed\n"); Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host); cls.demonum = -1; // not in the demo loop now cls.state = ca_connected; cls.signon = 0; // need all the signon messages before playing MSG_WriteByte (&cls.message, clc_nop); // NAT Fix from ProQuake } /* ===================== CL_SignonReply An svc_signonnum has been received, perform a client side setup ===================== */ void CL_SignonReply (void) { char str[8192]; Con_DPrintf ("CL_SignonReply: %i\n", cls.signon); switch (cls.signon) { case 1: MSG_WriteByte (&cls.message, clc_stringcmd); MSG_WriteString (&cls.message, "prespawn"); break; case 2: MSG_WriteByte (&cls.message, clc_stringcmd); MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string)); MSG_WriteByte (&cls.message, clc_stringcmd); MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15)); MSG_WriteByte (&cls.message, clc_stringcmd); sprintf (str, "spawn %s", cls.spawnparms); MSG_WriteString (&cls.message, str); break; case 3: MSG_WriteByte (&cls.message, clc_stringcmd); MSG_WriteString (&cls.message, "begin"); Cache_Report (); // print remaining memory break; case 4: SCR_EndLoadingPlaque (); // allow normal screen updates break; } } /* ===================== CL_NextDemo Called to play the next demo in the demo loop ===================== */ void CL_NextDemo (void) { char str[1024]; if (cls.demonum == -1) return; // don't play demos if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS) { cls.demonum = 0; if (!cls.demos[cls.demonum][0]) { Con_Printf ("No demos listed with startdemos\n"); cls.demonum = -1; CL_Disconnect(); return; } } SCR_BeginLoadingPlaque (); sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]); Cbuf_InsertText (str); cls.demonum++; } /* ============== CL_PrintEntities_f ============== */ void CL_PrintEntities_f (void) { entity_t *ent; int i; for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++) { Con_Printf ("%3i:",i); if (!ent->model) { Con_Printf ("EMPTY\n"); continue; } Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n" ,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]); } } /* =============== CL_AllocDlight =============== */ dlight_t *CL_AllocDlight (int key) { int i; dlight_t *dl; // first look for an exact key match if (key) { dl = cl_dlights; for (i=0 ; i<MAX_DLIGHTS ; i++, dl++) { if (dl->key == key) { memset (dl, 0, sizeof(*dl)); dl->key = key; dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc return dl; } } } // then look for anything else dl = cl_dlights; for (i=0 ; i<MAX_DLIGHTS ; i++, dl++) { if (dl->die < cl.time) { memset (dl, 0, sizeof(*dl)); dl->key = key; dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc return dl; } } dl = &cl_dlights[0]; memset (dl, 0, sizeof(*dl)); dl->key = key; dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc return dl; } /* =============== CL_DecayLights =============== */ void CL_DecayLights (void) { int i; dlight_t *dl; float time; time = cl.time - cl.oldtime; dl = cl_dlights; for (i=0 ; i<MAX_DLIGHTS ; i++, dl++) { if (dl->die < cl.time || !dl->radius) continue; dl->radius -= time*dl->decay; if (dl->radius < 0) dl->radius = 0; } } /* =============== CL_LerpPoint Determines the fraction between the last two messages that the objects should be put at. =============== */ float CL_LerpPoint (void) { float f, frac; f = cl.mtime[0] - cl.mtime[1]; if (!f || cls.timedemo || sv.active) { cl.time = cl.mtime[0]; return 1; } if (f > 0.1) // dropped packet, or start of demo { cl.mtime[1] = cl.mtime[0] - 0.1; f = 0.1; } frac = (cl.time - cl.mtime[1]) / f; if (frac < 0) { if (frac < -0.01) cl.time = cl.mtime[1]; frac = 0; } else if (frac > 1) { if (frac > 1.01) cl.time = cl.mtime[0]; frac = 1; } //johnfitz -- better nolerp behavior if (cl_nolerp.value) return 1; //johnfitz return frac; } /* =============== CL_RelinkEntities =============== */ void CL_RelinkEntities (void) { entity_t *ent; int i, j; float frac, f, d; vec3_t delta; float bobjrotate; vec3_t oldorg; dlight_t *dl; // determine partial update time frac = CL_LerpPoint (); cl_numvisedicts = 0; // // interpolate player info // for (i=0 ; i<3 ; i++) cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); if (cls.demoplayback) { // interpolate the angles for (j=0 ; j<3 ; j++) { d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; if (d > 180) d -= 360; else if (d < -180) d += 360; cl.viewangles[j] = cl.mviewangles[1][j] + frac*d; } } bobjrotate = anglemod(100*cl.time); // start on the entity after the world for (i=1,ent=cl_entities+1 ; i<cl.num_entities ; i++,ent++) { if (!ent->model) { // empty slot if (ent->forcelink) R_RemoveEfrags (ent); // just became empty continue; } // if the object wasn't included in the last packet, remove it if (ent->msgtime != cl.mtime[0]) { ent->model = NULL; ent->lerpflags |= LERP_RESETMOVE|LERP_RESETANIM; //johnfitz -- next time this entity slot is reused, the lerp will need to be reset continue; } VectorCopy (ent->origin, oldorg); if (ent->forcelink) { // the entity was not updated in the last message // so move to the final spot VectorCopy (ent->msg_origins[0], ent->origin); VectorCopy (ent->msg_angles[0], ent->angles); } else { // if the delta is large, assume a teleport and don't lerp f = frac; for (j=0 ; j<3 ; j++) { delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j]; if (delta[j] > 100 || delta[j] < -100) { f = 1; // assume a teleportation, not a motion ent->lerpflags |= LERP_RESETMOVE; //johnfitz -- don't lerp teleports } } //johnfitz -- don't cl_lerp entities that will be r_lerped if (r_lerpmove.value && (ent->lerpflags & LERP_MOVESTEP)) f = 1; //johnfitz // interpolate the origin and angles for (j=0 ; j<3 ; j++) { ent->origin[j] = ent->msg_origins[1][j] + f*delta[j]; d = ent->msg_angles[0][j] - ent->msg_angles[1][j]; if (d > 180) d -= 360; else if (d < -180) d += 360; ent->angles[j] = ent->msg_angles[1][j] + f*d; } } // rotate binary objects locally if (ent->model->flags & EF_ROTATE) ent->angles[1] = bobjrotate; if (ent->effects & EF_BRIGHTFIELD) R_EntityParticles (ent); if (ent->effects & EF_MUZZLEFLASH) { vec3_t fv, rv, uv; dl = CL_AllocDlight (i); VectorCopy (ent->origin, dl->origin); dl->origin[2] += 16; AngleVectors (ent->angles, fv, rv, uv); VectorMA (dl->origin, 18, fv, dl->origin); dl->radius = 200 + (rand()&31); dl->minlight = 32; dl->die = cl.time + 0.1; //johnfitz -- assume muzzle flash accompanied by muzzle flare, which looks bad when lerped if (r_lerpmodels.value != 2) { if (ent == &cl_entities[cl.viewentity]) cl.viewent.lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames else ent->lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames } //johnfitz } if (ent->effects & EF_BRIGHTLIGHT) { dl = CL_AllocDlight (i); VectorCopy (ent->origin, dl->origin); dl->origin[2] += 16; dl->radius = 400 + (rand()&31); dl->die = cl.time + 0.001; } if (ent->effects & EF_DIMLIGHT) { dl = CL_AllocDlight (i); VectorCopy (ent->origin, dl->origin); dl->radius = 200 + (rand()&31); dl->die = cl.time + 0.001; } if (ent->model->flags & EF_GIB) R_RocketTrail (oldorg, ent->origin, 2); else if (ent->model->flags & EF_ZOMGIB) R_RocketTrail (oldorg, ent->origin, 4); else if (ent->model->flags & EF_TRACER) R_RocketTrail (oldorg, ent->origin, 3); else if (ent->model->flags & EF_TRACER2) R_RocketTrail (oldorg, ent->origin, 5); else if (ent->model->flags & EF_ROCKET) { R_RocketTrail (oldorg, ent->origin, 0); dl = CL_AllocDlight (i); VectorCopy (ent->origin, dl->origin); dl->radius = 200; dl->die = cl.time + 0.01; } else if (ent->model->flags & EF_GRENADE) R_RocketTrail (oldorg, ent->origin, 1); else if (ent->model->flags & EF_TRACER3) R_RocketTrail (oldorg, ent->origin, 6); ent->forcelink = false; if (i == cl.viewentity && !chase_active.value) continue; if (cl_numvisedicts < MAX_VISEDICTS) { cl_visedicts[cl_numvisedicts] = ent; cl_numvisedicts++; } } } /* =============== CL_ReadFromServer Read all incoming data from the server =============== */ int CL_ReadFromServer (void) { int ret; extern int num_temp_entities; //johnfitz int num_beams = 0; //johnfitz int num_dlights = 0; //johnfitz beam_t *b; //johnfitz dlight_t *l; //johnfitz int i; //johnfitz cl.oldtime = cl.time; cl.time += host_frametime; do { ret = CL_GetMessage (); if (ret == -1) Host_Error ("CL_ReadFromServer: lost server connection"); if (!ret) break; cl.last_received_message = realtime; CL_ParseServerMessage (); } while (ret && cls.state == ca_connected); if (cl_shownet.value) Con_Printf ("\n"); CL_RelinkEntities (); CL_UpdateTEnts (); //johnfitz -- devstats //visedicts if (cl_numvisedicts > 256 && dev_peakstats.visedicts <= 256) Con_DWarning ("%i visedicts exceeds standard limit of 256.\n", cl_numvisedicts); dev_stats.visedicts = cl_numvisedicts; dev_peakstats.visedicts = q_max(cl_numvisedicts, dev_peakstats.visedicts); //temp entities if (num_temp_entities > 64 && dev_peakstats.tempents <= 64) Con_DWarning ("%i tempentities exceeds standard limit of 64.\n", num_temp_entities); dev_stats.tempents = num_temp_entities; dev_peakstats.tempents = q_max(num_temp_entities, dev_peakstats.tempents); //beams for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) if (b->model && b->endtime >= cl.time) num_beams++; if (num_beams > 24 && dev_peakstats.beams <= 24) Con_DWarning ("%i beams exceeded standard limit of 24.\n", num_beams); dev_stats.beams = num_beams; dev_peakstats.beams = q_max(num_beams, dev_peakstats.beams); //dlights for (i=0, l=cl_dlights ; i<MAX_DLIGHTS ; i++, l++) if (l->die >= cl.time && l->radius) num_dlights++; if (num_dlights > 32 && dev_peakstats.dlights <= 32) Con_DWarning ("%i dlights exceeded standard limit of 32.\n", num_dlights); dev_stats.dlights = num_dlights; dev_peakstats.dlights = q_max(num_dlights, dev_peakstats.dlights); //johnfitz // // bring the links up to date // return 0; } /* ================= CL_SendCmd ================= */ void CL_SendCmd (void) { usercmd_t cmd; if (cls.state != ca_connected) return; if (cls.signon == SIGNONS) { // get basic movement from keyboard CL_BaseMove (&cmd); // allow mice or other external controllers to add to the move IN_Move (&cmd); // send the unreliable message CL_SendMove (&cmd); } if (cls.demoplayback) { SZ_Clear (&cls.message); return; } // send the reliable message if (!cls.message.cursize) return; // no message at all if (!NET_CanSendMessage (cls.netcon)) { Con_DPrintf ("CL_SendCmd: can't send\n"); return; } if (NET_SendMessage (cls.netcon, &cls.message) == -1) Host_Error ("CL_SendCmd: lost server connection"); SZ_Clear (&cls.message); } /* ============= CL_Tracepos_f -- johnfitz display impact point of trace along VPN ============= */ void CL_Tracepos_f (void) { vec3_t v, w; VectorScale(vpn, 8192.0, v); TraceLine(r_refdef.vieworg, v, w); if (VectorLength(w) == 0) Con_Printf ("Tracepos: trace didn't hit anything\n"); else Con_Printf ("Tracepos: (%i %i %i)\n", (int)w[0], (int)w[1], (int)w[2]); } /* ============= CL_Viewpos_f -- johnfitz display client's position and angles ============= */ void CL_Viewpos_f (void) { #if 0 //camera position Con_Printf ("Viewpos: (%i %i %i) %i %i %i\n", (int)r_refdef.vieworg[0], (int)r_refdef.vieworg[1], (int)r_refdef.vieworg[2], (int)r_refdef.viewangles[PITCH], (int)r_refdef.viewangles[YAW], (int)r_refdef.viewangles[ROLL]); #else //player position Con_Printf ("Viewpos: (%i %i %i) %i %i %i\n", (int)cl_entities[cl.viewentity].origin[0], (int)cl_entities[cl.viewentity].origin[1], (int)cl_entities[cl.viewentity].origin[2], (int)cl.viewangles[PITCH], (int)cl.viewangles[YAW], (int)cl.viewangles[ROLL]); #endif } /* ================= CL_Init ================= */ void CL_Init (void) { SZ_Alloc (&cls.message, 1024); CL_InitInput (); CL_InitTEnts (); Cvar_RegisterVariable (&cl_name); Cvar_RegisterVariable (&cl_color); Cvar_RegisterVariable (&cl_upspeed); Cvar_RegisterVariable (&cl_forwardspeed); Cvar_RegisterVariable (&cl_backspeed); Cvar_RegisterVariable (&cl_sidespeed); Cvar_RegisterVariable (&cl_movespeedkey); Cvar_RegisterVariable (&cl_yawspeed); Cvar_RegisterVariable (&cl_pitchspeed); Cvar_RegisterVariable (&cl_anglespeedkey); Cvar_RegisterVariable (&cl_shownet); Cvar_RegisterVariable (&cl_nolerp); Cvar_RegisterVariable (&lookspring); Cvar_RegisterVariable (&lookstrafe); Cvar_RegisterVariable (&sensitivity); Cvar_RegisterVariable (&m_pitch); Cvar_RegisterVariable (&m_yaw); Cvar_RegisterVariable (&m_forward); Cvar_RegisterVariable (&m_side); Cvar_RegisterVariable (&cfg_unbindall); Cvar_RegisterVariable (&cl_maxpitch); //johnfitz -- variable pitch clamping Cvar_RegisterVariable (&cl_minpitch); //johnfitz -- variable pitch clamping Cmd_AddCommand ("entities", CL_PrintEntities_f); Cmd_AddCommand ("disconnect", CL_Disconnect_f); Cmd_AddCommand ("record", CL_Record_f); Cmd_AddCommand ("stop", CL_Stop_f); Cmd_AddCommand ("playdemo", CL_PlayDemo_f); Cmd_AddCommand ("timedemo", CL_TimeDemo_f); Cmd_AddCommand ("tracepos", CL_Tracepos_f); //johnfitz Cmd_AddCommand ("viewpos", CL_Viewpos_f); //johnfitz } ���������������������������������quakespasm-0.91.0/Quake/quakedef.h������������������������������������������������������������������0000644�0000000�0000000�00000020254�12537505372�015471� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __QUAKEDEFS_H #define __QUAKEDEFS_H // quakedef.h -- primary header for client #define QUAKE_GAME // as opposed to utilities #define VERSION 1.09 #define GLQUAKE_VERSION 1.00 #define D3DQUAKE_VERSION 0.01 #define WINQUAKE_VERSION 0.996 #define LINUX_VERSION 1.30 #define X11_VERSION 1.10 #define FITZQUAKE_VERSION 0.85 //johnfitz #define QUAKESPASM_VERSION 0.91 #define QUAKESPASM_VER_PATCH 0 // helper to print a string like 0.91.0 //define PARANOID // speed sapping error checking #define GAMENAME "id1" // directory to look in by default #include "q_stdinc.h" // !!! if this is changed, it must be changed in d_ifacea.h too !!! #define CACHE_SIZE 32 // used to align key data structures #define Q_UNUSED(x) (x = x) // for pesky compiler / lint warnings #define MINIMUM_MEMORY 0x550000 #define MINIMUM_MEMORY_LEVELPAK (MINIMUM_MEMORY + 0x100000) #define MAX_NUM_ARGVS 50 // up / down #define PITCH 0 // left / right #define YAW 1 // fall over #define ROLL 2 #define MAX_QPATH 64 // max length of a quake game pathname #define ON_EPSILON 0.1 // point on plane side epsilon #define DIST_EPSILON (0.03125) // 1/32 epsilon to keep floating point happy (moved from world.c) #define MAX_MSGLEN 64000 // max length of a reliable message //ericw -- was 32000 #define MAX_DATAGRAM 32000 // max length of unreliable message //johnfitz -- was 1024 #define DATAGRAM_MTU 1400 // johnfitz -- actual limit for unreliable messages to nonlocal clients // // per-level limits // #define MIN_EDICTS 256 // johnfitz -- lowest allowed value for max_edicts cvar #define MAX_EDICTS 32000 // johnfitz -- highest allowed value for max_edicts cvar // ents past 8192 can't play sounds in the standard protocol #define MAX_LIGHTSTYLES 64 #define MAX_MODELS 2048 // johnfitz -- was 256 #define MAX_SOUNDS 2048 // johnfitz -- was 256 #define SAVEGAME_COMMENT_LENGTH 39 #define MAX_STYLESTRING 64 // // stats are integers communicated to the client by the server // #define MAX_CL_STATS 32 #define STAT_HEALTH 0 #define STAT_FRAGS 1 #define STAT_WEAPON 2 #define STAT_AMMO 3 #define STAT_ARMOR 4 #define STAT_WEAPONFRAME 5 #define STAT_SHELLS 6 #define STAT_NAILS 7 #define STAT_ROCKETS 8 #define STAT_CELLS 9 #define STAT_ACTIVEWEAPON 10 #define STAT_TOTALSECRETS 11 #define STAT_TOTALMONSTERS 12 #define STAT_SECRETS 13 // bumped on client side by svc_foundsecret #define STAT_MONSTERS 14 // bumped by svc_killedmonster // stock defines // #define IT_SHOTGUN 1 #define IT_SUPER_SHOTGUN 2 #define IT_NAILGUN 4 #define IT_SUPER_NAILGUN 8 #define IT_GRENADE_LAUNCHER 16 #define IT_ROCKET_LAUNCHER 32 #define IT_LIGHTNING 64 #define IT_SUPER_LIGHTNING 128 #define IT_SHELLS 256 #define IT_NAILS 512 #define IT_ROCKETS 1024 #define IT_CELLS 2048 #define IT_AXE 4096 #define IT_ARMOR1 8192 #define IT_ARMOR2 16384 #define IT_ARMOR3 32768 #define IT_SUPERHEALTH 65536 #define IT_KEY1 131072 #define IT_KEY2 262144 #define IT_INVISIBILITY 524288 #define IT_INVULNERABILITY 1048576 #define IT_SUIT 2097152 #define IT_QUAD 4194304 #define IT_SIGIL1 (1<<28) #define IT_SIGIL2 (1<<29) #define IT_SIGIL3 (1<<30) #define IT_SIGIL4 (1<<31) //=========================================== //rogue changed and added defines #define RIT_SHELLS 128 #define RIT_NAILS 256 #define RIT_ROCKETS 512 #define RIT_CELLS 1024 #define RIT_AXE 2048 #define RIT_LAVA_NAILGUN 4096 #define RIT_LAVA_SUPER_NAILGUN 8192 #define RIT_MULTI_GRENADE 16384 #define RIT_MULTI_ROCKET 32768 #define RIT_PLASMA_GUN 65536 #define RIT_ARMOR1 8388608 #define RIT_ARMOR2 16777216 #define RIT_ARMOR3 33554432 #define RIT_LAVA_NAILS 67108864 #define RIT_PLASMA_AMMO 134217728 #define RIT_MULTI_ROCKETS 268435456 #define RIT_SHIELD 536870912 #define RIT_ANTIGRAV 1073741824 #define RIT_SUPERHEALTH 2147483648 //MED 01/04/97 added hipnotic defines //=========================================== //hipnotic added defines #define HIT_PROXIMITY_GUN_BIT 16 #define HIT_MJOLNIR_BIT 7 #define HIT_LASER_CANNON_BIT 23 #define HIT_PROXIMITY_GUN (1<<HIT_PROXIMITY_GUN_BIT) #define HIT_MJOLNIR (1<<HIT_MJOLNIR_BIT) #define HIT_LASER_CANNON (1<<HIT_LASER_CANNON_BIT) #define HIT_WETSUIT (1<<(23+2)) #define HIT_EMPATHY_SHIELDS (1<<(23+3)) //=========================================== #define MAX_SCOREBOARD 16 #define MAX_SCOREBOARDNAME 32 #define SOUND_CHANNELS 8 typedef struct { const char *basedir; const char *userdir; // user's directory on UNIX platforms. // if user directories are enabled, basedir // and userdir will point to different // memory locations, otherwise to the same. int argc; char **argv; void *membase; int memsize; int numcpus; } quakeparms_t; #include "common.h" #include "bspfile.h" #include "sys.h" #include "zone.h" #include "mathlib.h" #include "cvar.h" #include "protocol.h" #include "net.h" #include "cmd.h" #include "crc.h" #include "progs.h" #include "server.h" #include "platform.h" #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #include <SDL2/SDL_opengl.h> #else #include <SDL/SDL.h> #include <SDL/SDL_opengl.h> #endif #else #include "SDL.h" #include "SDL_opengl.h" #endif #ifndef APIENTRY #define APIENTRY #endif #include "console.h" #include "wad.h" #include "vid.h" #include "screen.h" #include "draw.h" #include "render.h" #include "view.h" #include "sbar.h" #include "q_sound.h" #include "client.h" #include "gl_model.h" #include "world.h" #include "image.h" //johnfitz #include "gl_texmgr.h" //johnfitz #include "input.h" #include "keys.h" #include "menu.h" #include "cdaudio.h" #include "glquake.h" //============================================================================= // the host system specifies the base of the directory tree, the // command line parms passed to the program, and the amount of memory // available for the program to use extern qboolean noclip_anglehack; // // host // extern quakeparms_t *host_parms; extern cvar_t sys_ticrate; extern cvar_t sys_throttle; extern cvar_t sys_nostdout; extern cvar_t developer; extern cvar_t max_edicts; //johnfitz extern qboolean host_initialized; // true if into command execution extern double host_frametime; extern byte *host_colormap; extern int host_framecount; // incremented every frame, never reset extern double realtime; // not bounded in any way, changed at // start of every frame, never reset void Host_ClearMemory (void); void Host_ServerFrame (void); void Host_InitCommands (void); void Host_Init (void); void Host_Shutdown(void); void Host_Callback_Notify (cvar_t *var); /* callback function for CVAR_NOTIFY */ void Host_Error (const char *error, ...) __attribute__((__format__(__printf__,1,2), __noreturn__)); void Host_EndGame (const char *message, ...) __attribute__((__format__(__printf__,1,2), __noreturn__)); void Host_Frame (float time); void Host_Quit_f (void); void Host_ClientCommands (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); void Host_ShutdownServer (qboolean crash); void Host_WriteConfiguration (void); void ExtraMaps_Init (void); void Modlist_Init (void); void DemoList_Init (void); void DemoList_Rebuild (void); extern int current_skill; // skill level for currently loaded level (in case // the user changes the cvar while the level is // running, this reflects the level actually in use) extern qboolean isDedicated; extern int minimum_memory; #endif /* __QUAKEDEFS_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/Makefile��������������������������������������������������������������������0000644�0000000�0000000�00000014054�12407362617�015173� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# GNU Makefile for QuakeSpasm unix targets, Sep. 10, 2014 # You need the SDL library fully installed. # "make DEBUG=1" to build a debug client. # "make SDL_CONFIG=/path/to/sdl-config" for unusual SDL installations. # "make DO_USERDIRS=1" to enable user directories support # Enable/Disable user directories support DO_USERDIRS=0 ### Enable/Disable SDL2 USE_SDL2=0 ### Enable/Disable codecs for streaming music support USE_CODEC_WAVE=1 USE_CODEC_FLAC=0 USE_CODEC_MP3=1 USE_CODEC_VORBIS=1 USE_CODEC_OPUS=0 # either mikmod (preferred) or modplug, not both USE_CODEC_MIKMOD=0 USE_CODEC_MODPLUG=0 USE_CODEC_UMX=0 # which library to use for mp3 decoding: mad or mpg123 MP3LIB=mad # which library to use for ogg decoding: vorbis or tremor VORBISLIB=vorbis # --------------------------- # Helper functions # --------------------------- check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi;) # --------------------------- HOST_OS := $(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]') DEBUG ?= 0 # --------------------------- # build variables # --------------------------- CC ?= gcc LINKER = $(CC) STRIP ?= strip #CPUFLAGS= -mtune=i686 #CPUFLAGS= -march=pentium4 #CPUFLAGS= -mtune=k8 #CPUFLAGS= -march=atom CPUFLAGS= LDFLAGS = DFLAGS ?= CFLAGS ?= -Wall -Wno-trigraphs CFLAGS += $(CPUFLAGS) ifneq ($(DEBUG),0) DFLAGS += -DDEBUG CFLAGS += -g do_strip= else DFLAGS += -DNDEBUG CFLAGS += -O2 CFLAGS += $(call check_gcc,-fweb,) CFLAGS += $(call check_gcc,-frename-registers,) cmd_strip=$(STRIP) $(1) define do_strip $(call cmd_strip,$(1)); endef endif ifeq ($(DO_USERDIRS),1) CFLAGS += -DDO_USERDIRS=1 endif ### X11BASE only gets used if its in an unusual place X11DIRS := /usr/X11R7 /usr/local/X11R7 /usr/X11R6 /usr/local/X11R6 X11BASE_GUESS := $(shell \ if [ -e /usr/include/X11/Xlib.h ] && \ [ -e /usr/lib/libX11.a ]; then exit 0; fi; \ if [ -e /usr/local/include/X11/Xlib.h ] && \ [ -e /usr/local/lib/libX11.a ]; then exit 0; fi; \ for DIR in $(X11DIRS); do \ if [ -e $$DIR/include/X11/Xlib.h ] && \ [ -e $$DIR/lib/libX11.a ]; then echo $$DIR; break; fi; \ done ) X11BASE ?= $(X11BASE_GUESS) ifneq ($(X11BASE),) LDFLAGS+= -L$(X11BASE)/lib CFLAGS += -I$(X11BASE)/include endif ifeq ($(USE_SDL2),1) CFLAGS += -DUSE_SDL2 endif ifeq ($(USE_SDL2),1) SDL_CONFIG ?= sdl2-config else SDL_CONFIG ?= sdl-config endif SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags) SDL_LIBS := $(shell $(SDL_CONFIG) --libs) ifeq ($(HOST_OS),sunos) NET_LIBS :=-lsocket -lnsl -lresolv else NET_LIBS := endif ifneq ($(VORBISLIB),vorbis) ifneq ($(VORBISLIB),tremor) $(error Invalid VORBISLIB setting) endif endif ifneq ($(MP3LIB),mpg123) ifneq ($(MP3LIB),mad) $(error Invalid MP3LIB setting) endif endif ifeq ($(MP3LIB),mad) mp3_obj=snd_mp3.o lib_mp3dec=-lmad endif ifeq ($(MP3LIB),mpg123) mp3_obj=snd_mpg123.o lib_mp3dec=-lmpg123 endif ifeq ($(VORBISLIB),vorbis) cpp_vorbisdec= lib_vorbisdec=-lvorbisfile -lvorbis -logg endif ifeq ($(VORBISLIB),tremor) cpp_vorbisdec=-DVORBIS_USE_TREMOR lib_vorbisdec=-lvorbisidec -logg endif CODECLIBS := ifeq ($(USE_CODEC_WAVE),1) CFLAGS+= -DUSE_CODEC_WAVE endif ifeq ($(USE_CODEC_FLAC),1) CFLAGS+= -DUSE_CODEC_FLAC CODECLIBS+= -lFLAC endif ifeq ($(USE_CODEC_OPUS),1) # opus and opusfile put their *.h under <includedir>/opus, # but they include the headers without the opus directory # prefix and rely on pkg-config. ewww... CFLAGS+= -DUSE_CODEC_OPUS CFLAGS+= $(shell pkg-config --cflags opusfile) CODECLIBS+= $(shell pkg-config --libs opusfile) endif ifeq ($(USE_CODEC_VORBIS),1) CFLAGS+= -DUSE_CODEC_VORBIS $(cpp_vorbisdec) CODECLIBS+= $(lib_vorbisdec) endif ifeq ($(USE_CODEC_MP3),1) CFLAGS+= -DUSE_CODEC_MP3 CODECLIBS+= $(lib_mp3dec) endif ifeq ($(USE_CODEC_MIKMOD),1) CFLAGS+= -DUSE_CODEC_MIKMOD CODECLIBS+= -lmikmod endif ifeq ($(USE_CODEC_MODPLUG),1) CFLAGS+= -DUSE_CODEC_MODPLUG CODECLIBS+= -lmodplug endif ifeq ($(USE_CODEC_UMX),1) CFLAGS+= -DUSE_CODEC_UMX endif COMMON_LIBS:= -lm -lGL LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODECLIBS) # --------------------------- # targets # --------------------------- .PHONY: clean debug release DEFAULT_TARGET := quakespasm # --------------------------- # rules # --------------------------- %.o: %.c $(CC) $(DFLAGS) -c $(CFLAGS) $(SDL_CFLAGS) -o $@ $^ # ---------------------------------------------------------------------------- # objects # ---------------------------------------------------------------------------- MUSIC_OBJS:= bgmusic.o \ snd_codec.o \ snd_flac.o \ snd_wave.o \ snd_vorbis.o \ snd_opus.o \ $(mp3_obj) \ snd_mikmod.o \ snd_modplug.o \ snd_umx.o COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS) SYSOBJ_SND := snd_sdl.o SYSOBJ_CDA := cd_sdl.o SYSOBJ_INPUT := in_sdl.o SYSOBJ_GL_VID:= gl_vidsdl.o SYSOBJ_NET := net_bsd.o net_udp.o SYSOBJ_SYS := pl_linux.o sys_sdl_unix.o SYSOBJ_MAIN:= main_sdl.o SYSOBJ_RES := GLOBJS = \ gl_refrag.o \ gl_rlight.o \ gl_rmain.o \ gl_fog.o \ gl_rmisc.o \ r_part.o \ r_world.o \ gl_screen.o \ gl_sky.o \ gl_warp.o \ $(SYSOBJ_GL_VID) \ gl_draw.o \ image.o \ gl_texmgr.o \ gl_mesh.o \ r_sprite.o \ r_alias.o \ r_brush.o \ gl_model.o OBJS := strlcat.o \ strlcpy.o \ $(GLOBJS) \ $(SYSOBJ_INPUT) \ $(COMOBJ_SND) \ $(SYSOBJ_SND) \ $(SYSOBJ_CDA) \ $(SYSOBJ_NET) \ net_dgrm.o \ net_loop.o \ net_main.o \ chase.o \ cl_demo.o \ cl_input.o \ cl_main.o \ cl_parse.o \ cl_tent.o \ console.o \ keys.o \ menu.o \ sbar.o \ view.o \ wad.o \ cmd.o \ common.o \ crc.o \ cvar.o \ cfgfile.o \ host.o \ host_cmd.o \ mathlib.o \ pr_cmds.o \ pr_edict.o \ pr_exec.o \ sv_main.o \ sv_move.o \ sv_phys.o \ sv_user.o \ world.o \ zone.o \ $(SYSOBJ_SYS) $(SYSOBJ_MAIN) $(SYSOBJ_RES) # ------------------------ # Linux build rules # ------------------------ quakespasm: $(OBJS) $(LINKER) $(OBJS) $(LDFLAGS) $(LIBS) $(SDL_LIBS) -o $@ $(call do_strip,$@) release: quakespasm debug: $(error Use "make DEBUG=1") clean: rm -f $(shell find . \( -name '*~' -o -name '#*#' -o -name '*.o' -o -name '*.res' -o -name $(DEFAULT_TARGET) \) -print) install: quakespasm cp quakespasm /usr/local/games/quake ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sv_phys.c�������������������������������������������������������������������0000644�0000000�0000000�00000066773�12407762022�015403� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_phys.c #include "quakedef.h" /* pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move. onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS corpses are SOLID_NOT and MOVETYPE_TOSS crates are SOLID_BBOX and MOVETYPE_TOSS walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY solid_edge items only clip against bsp models. */ cvar_t sv_friction = {"sv_friction","4",CVAR_NOTIFY|CVAR_SERVERINFO}; cvar_t sv_stopspeed = {"sv_stopspeed","100",CVAR_NONE}; cvar_t sv_gravity = {"sv_gravity","800",CVAR_NOTIFY|CVAR_SERVERINFO}; cvar_t sv_maxvelocity = {"sv_maxvelocity","2000",CVAR_NONE}; cvar_t sv_nostep = {"sv_nostep","0",CVAR_NONE}; cvar_t sv_freezenonclients = {"sv_freezenonclients","0",CVAR_NONE}; #define MOVE_EPSILON 0.01 void SV_Physics_Toss (edict_t *ent); /* ================ SV_CheckAllEnts ================ */ void SV_CheckAllEnts (void) { int e; edict_t *check; // see if any solid entities are inside the final position check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; if (SV_TestEntityPosition (check)) Con_Printf ("entity in invalid position\n"); } } /* ================ SV_CheckVelocity ================ */ void SV_CheckVelocity (edict_t *ent) { int i; // // bound velocity // for (i=0 ; i<3 ; i++) { if (IS_NAN(ent->v.velocity[i])) { Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(ent->v.classname)); ent->v.velocity[i] = 0; } if (IS_NAN(ent->v.origin[i])) { Con_Printf ("Got a NaN origin on %s\n", PR_GetString(ent->v.classname)); ent->v.origin[i] = 0; } if (ent->v.velocity[i] > sv_maxvelocity.value) ent->v.velocity[i] = sv_maxvelocity.value; else if (ent->v.velocity[i] < -sv_maxvelocity.value) ent->v.velocity[i] = -sv_maxvelocity.value; } } /* ============= SV_RunThink Runs thinking code if time. There is some play in the exact time the think function will be called, because it is called before any movement is done in a frame. Not used for pushmove objects, because they must be exact. Returns false if the entity removed itself. ============= */ qboolean SV_RunThink (edict_t *ent) { float thinktime; float oldframe; //johnfitz int i; //johnfitz thinktime = ent->v.nextthink; if (thinktime <= 0 || thinktime > sv.time + host_frametime) return true; if (thinktime < sv.time) thinktime = sv.time; // don't let things stay in the past. // it is possible to start that way // by a trigger with a local time. oldframe = ent->v.frame; //johnfitz ent->v.nextthink = 0; pr_global_struct->time = thinktime; pr_global_struct->self = EDICT_TO_PROG(ent); pr_global_struct->other = EDICT_TO_PROG(sv.edicts); PR_ExecuteProgram (ent->v.think); //johnfitz -- PROTOCOL_FITZQUAKE //capture interval to nextthink here and send it to client for better //lerp timing, but only if interval is not 0.1 (which client assumes) ent->sendinterval = false; if (!ent->free && ent->v.nextthink && (ent->v.movetype == MOVETYPE_STEP || ent->v.frame != oldframe)) { i = Q_rint((ent->v.nextthink-thinktime)*255); if (i >= 0 && i < 256 && i != 25 && i != 26) //25 and 26 are close enough to 0.1 to not send ent->sendinterval = true; } //johnfitz return !ent->free; } /* ================== SV_Impact Two entities have touched, so run their touch functions ================== */ void SV_Impact (edict_t *e1, edict_t *e2) { int old_self, old_other; old_self = pr_global_struct->self; old_other = pr_global_struct->other; pr_global_struct->time = sv.time; if (e1->v.touch && e1->v.solid != SOLID_NOT) { pr_global_struct->self = EDICT_TO_PROG(e1); pr_global_struct->other = EDICT_TO_PROG(e2); PR_ExecuteProgram (e1->v.touch); } if (e2->v.touch && e2->v.solid != SOLID_NOT) { pr_global_struct->self = EDICT_TO_PROG(e2); pr_global_struct->other = EDICT_TO_PROG(e1); PR_ExecuteProgram (e2->v.touch); } pr_global_struct->self = old_self; pr_global_struct->other = old_other; } /* ================== ClipVelocity Slide off of the impacting object returns the blocked flags (1 = floor, 2 = step / wall) ================== */ #define STOP_EPSILON 0.1 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) { float backoff; float change; int i, blocked; blocked = 0; if (normal[2] > 0) blocked |= 1; // floor if (!normal[2]) blocked |= 2; // step backoff = DotProduct (in, normal) * overbounce; for (i=0 ; i<3 ; i++) { change = normal[i]*backoff; out[i] = in[i] - change; if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) out[i] = 0; } return blocked; } /* ============ SV_FlyMove The basic solid body movement clip that slides along multiple planes Returns the clipflags if the velocity was modified (hit something solid) 1 = floor 2 = wall / step 4 = dead stop If steptrace is not NULL, the trace of any vertical wall hit will be stored ============ */ #define MAX_CLIP_PLANES 5 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy (ent->v.velocity, original_velocity); VectorCopy (ent->v.velocity, primal_velocity); numplanes = 0; time_left = time; for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) { if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2]) break; for (i=0 ; i<3 ; i++) end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); if (trace.allsolid) { // entity is trapped in another solid VectorCopy (vec3_origin, ent->v.velocity); return 3; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, ent->v.origin); VectorCopy (ent->v.velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance if (!trace.ent) Sys_Error ("SV_FlyMove: !trace.ent"); if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if (trace.ent->v.solid == SOLID_BSP) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = EDICT_TO_PROG(trace.ent); } } if (!trace.plane.normal[2]) { blocked |= 2; // step if (steptrace) *steptrace = trace; // save for player extrafriction } // // run the impact function // SV_Impact (ent, trace.ent); if (ent->free) break; // removed by the impact function time_left -= time_left * trace.fraction; // cliped to another plane if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen VectorCopy (vec3_origin, ent->v.velocity); return 3; } VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // // modify original_velocity so it parallels all of the clip planes // for (i=0 ; i<numplanes ; i++) { ClipVelocity (original_velocity, planes[i], new_velocity, 1); for (j=0 ; j<numplanes ; j++) if (j != i) { if (DotProduct (new_velocity, planes[j]) < 0) break; // not ok } if (j == numplanes) break; } if (i != numplanes) { // go along this plane VectorCopy (new_velocity, ent->v.velocity); } else { // go along the crease if (numplanes != 2) { // Con_Printf ("clip velocity, numplanes == %i\n",numplanes); VectorCopy (vec3_origin, ent->v.velocity); return 7; } CrossProduct (planes[0], planes[1], dir); d = DotProduct (dir, ent->v.velocity); VectorScale (dir, d, ent->v.velocity); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if (DotProduct (ent->v.velocity, primal_velocity) <= 0) { VectorCopy (vec3_origin, ent->v.velocity); return blocked; } } return blocked; } /* ============ SV_AddGravity ============ */ void SV_AddGravity (edict_t *ent) { float ent_gravity; eval_t *val; val = GetEdictFieldValue(ent, "gravity"); if (val && val->_float) ent_gravity = val->_float; else ent_gravity = 1.0; ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime; } /* =============================================================================== PUSHMOVE =============================================================================== */ /* ============ SV_PushEntity Does not change the entities velocity at all ============ */ trace_t SV_PushEntity (edict_t *ent, vec3_t push) { trace_t trace; vec3_t end; VectorAdd (ent->v.origin, push, end); if (ent->v.movetype == MOVETYPE_FLYMISSILE) trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) // only clip against bmodels trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); else trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); VectorCopy (trace.endpos, ent->v.origin); SV_LinkEdict (ent, true); if (trace.ent) SV_Impact (ent, trace.ent); return trace; } /* ============ SV_PushMove ============ */ void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; edict_t **moved_edict; //johnfitz -- dynamically allocate vec3_t *moved_from; //johnfitz -- dynamically allocate int mark; //johnfitz if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); //johnfitz -- dynamically allocate mark = Hunk_LowMark (); moved_edict = (edict_t **) Hunk_Alloc (sv.num_edicts*sizeof(edict_t *)); moved_from = (vec3_t *) Hunk_Alloc (sv.num_edicts*sizeof(vec3_t)); //johnfitz // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definately be moved if ( ! ( ((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher) ) { if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } // remove the onground flag for non-players if (check->v.movetype != MOVETYPE_WALK) check->v.flags = (int)check->v.flags & ~FL_ONGROUND; VectorCopy (check->v.origin, entorig); VectorCopy (check->v.origin, moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); pusher->v.solid = SOLID_BSP; // if it is still inside the pusher, block block = SV_TestEntityPosition (check); if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; VectorCopy (check->v.mins, check->v.maxs); continue; } VectorCopy (entorig, check->v.origin); SV_LinkEdict (check, true); VectorCopy (pushorig, pusher->v.origin); SV_LinkEdict (pusher, false); pusher->v.ltime -= movetime; // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) { pr_global_struct->self = EDICT_TO_PROG(pusher); pr_global_struct->other = EDICT_TO_PROG(check); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } Hunk_FreeToLowMark (mark); //johnfitz return; } } Hunk_FreeToLowMark (mark); //johnfitz } /* ================ SV_Physics_Pusher ================ */ void SV_Physics_Pusher (edict_t *ent) { float thinktime; float oldltime; float movetime; oldltime = ent->v.ltime; thinktime = ent->v.nextthink; if (thinktime < ent->v.ltime + host_frametime) { movetime = thinktime - ent->v.ltime; if (movetime < 0) movetime = 0; } else movetime = host_frametime; if (movetime) { SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked } if (thinktime > oldltime && thinktime <= ent->v.ltime) { ent->v.nextthink = 0; pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(ent); pr_global_struct->other = EDICT_TO_PROG(sv.edicts); PR_ExecuteProgram (ent->v.think); if (ent->free) return; } } /* =============================================================================== CLIENT MOVEMENT =============================================================================== */ /* ============= SV_CheckStuck This is a big hack to try and fix the rare case of getting stuck in the world clipping hull. ============= */ void SV_CheckStuck (edict_t *ent) { int i, j; int z; vec3_t org; if (!SV_TestEntityPosition(ent)) { VectorCopy (ent->v.origin, ent->v.oldorigin); return; } VectorCopy (ent->v.origin, org); VectorCopy (ent->v.oldorigin, ent->v.origin); if (!SV_TestEntityPosition(ent)) { Con_DPrintf ("Unstuck.\n"); SV_LinkEdict (ent, true); return; } for (z=0 ; z< 18 ; z++) for (i=-1 ; i <= 1 ; i++) for (j=-1 ; j <= 1 ; j++) { ent->v.origin[0] = org[0] + i; ent->v.origin[1] = org[1] + j; ent->v.origin[2] = org[2] + z; if (!SV_TestEntityPosition(ent)) { Con_DPrintf ("Unstuck.\n"); SV_LinkEdict (ent, true); return; } } VectorCopy (org, ent->v.origin); Con_DPrintf ("player is stuck.\n"); } /* ============= SV_CheckWater ============= */ qboolean SV_CheckWater (edict_t *ent) { vec3_t point; int cont; point[0] = ent->v.origin[0]; point[1] = ent->v.origin[1]; point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; ent->v.waterlevel = 0; ent->v.watertype = CONTENTS_EMPTY; cont = SV_PointContents (point); if (cont <= CONTENTS_WATER) { ent->v.watertype = cont; ent->v.waterlevel = 1; point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5; cont = SV_PointContents (point); if (cont <= CONTENTS_WATER) { ent->v.waterlevel = 2; point[2] = ent->v.origin[2] + ent->v.view_ofs[2]; cont = SV_PointContents (point); if (cont <= CONTENTS_WATER) ent->v.waterlevel = 3; } } return ent->v.waterlevel > 1; } /* ============ SV_WallFriction ============ */ void SV_WallFriction (edict_t *ent, trace_t *trace) { vec3_t forward, right, up; float d, i; vec3_t into, side; AngleVectors (ent->v.v_angle, forward, right, up); d = DotProduct (trace->plane.normal, forward); d += 0.5; if (d >= 0) return; // cut the tangential velocity i = DotProduct (trace->plane.normal, ent->v.velocity); VectorScale (trace->plane.normal, i, into); VectorSubtract (ent->v.velocity, into, side); ent->v.velocity[0] = side[0] * (1 + d); ent->v.velocity[1] = side[1] * (1 + d); } /* ===================== SV_TryUnstick Player has come to a dead stop, possibly due to the problem with limited float precision at some angle joins in the BSP hull. Try fixing by pushing one pixel in each direction. This is a hack, but in the interest of good gameplay... ====================== */ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) { int i; vec3_t oldorg; vec3_t dir; int clip; trace_t steptrace; VectorCopy (ent->v.origin, oldorg); VectorCopy (vec3_origin, dir); for (i=0 ; i<8 ; i++) { // try pushing a little in an axial direction switch (i) { case 0: dir[0] = 2; dir[1] = 0; break; case 1: dir[0] = 0; dir[1] = 2; break; case 2: dir[0] = -2; dir[1] = 0; break; case 3: dir[0] = 0; dir[1] = -2; break; case 4: dir[0] = 2; dir[1] = 2; break; case 5: dir[0] = -2; dir[1] = 2; break; case 6: dir[0] = 2; dir[1] = -2; break; case 7: dir[0] = -2; dir[1] = -2; break; } SV_PushEntity (ent, dir); // retry the original move ent->v.velocity[0] = oldvel[0]; ent->v. velocity[1] = oldvel[1]; ent->v. velocity[2] = 0; clip = SV_FlyMove (ent, 0.1, &steptrace); if ( fabs(oldorg[1] - ent->v.origin[1]) > 4 || fabs(oldorg[0] - ent->v.origin[0]) > 4 ) { //Con_DPrintf ("unstuck!\n"); return clip; } // go back to the original pos and try again VectorCopy (oldorg, ent->v.origin); } VectorCopy (vec3_origin, ent->v.velocity); return 7; // still not moving } /* ===================== SV_WalkMove Only used by players ====================== */ #define STEPSIZE 18 void SV_WalkMove (edict_t *ent) { vec3_t upmove, downmove; vec3_t oldorg, oldvel; vec3_t nosteporg, nostepvel; int clip; int oldonground; trace_t steptrace, downtrace; // // do a regular slide move unless it looks like you ran into a step // oldonground = (int)ent->v.flags & FL_ONGROUND; ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; VectorCopy (ent->v.origin, oldorg); VectorCopy (ent->v.velocity, oldvel); clip = SV_FlyMove (ent, host_frametime, &steptrace); if ( !(clip & 2) ) return; // move didn't block on a step if (!oldonground && ent->v.waterlevel == 0) return; // don't stair up while jumping if (ent->v.movetype != MOVETYPE_WALK) return; // gibbed by a trigger if (sv_nostep.value) return; if ( (int)sv_player->v.flags & FL_WATERJUMP ) return; VectorCopy (ent->v.origin, nosteporg); VectorCopy (ent->v.velocity, nostepvel); // // try moving up and forward to go up a step // VectorCopy (oldorg, ent->v.origin); // back to start pos VectorCopy (vec3_origin, upmove); VectorCopy (vec3_origin, downmove); upmove[2] = STEPSIZE; downmove[2] = -STEPSIZE + oldvel[2]*host_frametime; // move up SV_PushEntity (ent, upmove); // FIXME: don't link? // move forward ent->v.velocity[0] = oldvel[0]; ent->v. velocity[1] = oldvel[1]; ent->v. velocity[2] = 0; clip = SV_FlyMove (ent, host_frametime, &steptrace); // check for stuckness, possibly due to the limited precision of floats // in the clipping hulls if (clip) { if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 ) { // stepping up didn't make any progress clip = SV_TryUnstick (ent, oldvel); } } // extra friction based on view angle if ( clip & 2 ) SV_WallFriction (ent, &steptrace); // move down downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link? if (downtrace.plane.normal[2] > 0.7) { if (ent->v.solid == SOLID_BSP) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = EDICT_TO_PROG(downtrace.ent); } } else { // if the push down didn't end up on good ground, use the move without // the step up. This happens near wall / slope combinations, and can // cause the player to hop up higher on a slope too steep to climb VectorCopy (nosteporg, ent->v.origin); VectorCopy (nostepvel, ent->v.velocity); } } /* ================ SV_Physics_Client Player character actions ================ */ void SV_Physics_Client (edict_t *ent, int num) { if ( ! svs.clients[num-1].active ) return; // unconnected slot // // call standard client pre-think // pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(ent); PR_ExecuteProgram (pr_global_struct->PlayerPreThink); // // do a move // SV_CheckVelocity (ent); // // decide which move function to call // switch ((int)ent->v.movetype) { case MOVETYPE_NONE: if (!SV_RunThink (ent)) return; break; case MOVETYPE_WALK: if (!SV_RunThink (ent)) return; if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) ) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); break; case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: SV_Physics_Toss (ent); break; case MOVETYPE_FLY: if (!SV_RunThink (ent)) return; SV_FlyMove (ent, host_frametime, NULL); break; case MOVETYPE_NOCLIP: if (!SV_RunThink (ent)) return; VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); break; default: Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype); } // // call standard player post-think // SV_LinkEdict (ent, true); pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(ent); PR_ExecuteProgram (pr_global_struct->PlayerPostThink); } //============================================================================ /* ============= SV_Physics_None Non moving objects can only think ============= */ void SV_Physics_None (edict_t *ent) { // regular thinking SV_RunThink (ent); } /* ============= SV_Physics_Noclip A moving object that doesn't obey physics ============= */ void SV_Physics_Noclip (edict_t *ent) { // regular thinking if (!SV_RunThink (ent)) return; VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); SV_LinkEdict (ent, false); } /* ============================================================================== TOSS / BOUNCE ============================================================================== */ /* ============= SV_CheckWaterTransition ============= */ void SV_CheckWaterTransition (edict_t *ent) { int cont; cont = SV_PointContents (ent->v.origin); if (!ent->v.watertype) { // just spawned here ent->v.watertype = cont; ent->v.waterlevel = 1; return; } if (cont <= CONTENTS_WATER) { if (ent->v.watertype == CONTENTS_EMPTY) { // just crossed into water SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); } ent->v.watertype = cont; ent->v.waterlevel = 1; } else { if (ent->v.watertype != CONTENTS_EMPTY) { // just crossed into water SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); } ent->v.watertype = CONTENTS_EMPTY; ent->v.waterlevel = cont; } } /* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; // regular thinking if (!SV_RunThink (ent)) return; // if onground, return without moving if ( ((int)ent->v.flags & FL_ONGROUND) ) return; SV_CheckVelocity (ent); // add gravity if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); // move angles VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); // move origin VectorScale (ent->v.velocity, host_frametime, move); trace = SV_PushEntity (ent, move); if (trace.fraction == 1) return; if (ent->free) return; if (ent->v.movetype == MOVETYPE_BOUNCE) backoff = 1.5; else backoff = 1; ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.7) { if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = EDICT_TO_PROG(trace.ent); VectorCopy (vec3_origin, ent->v.velocity); VectorCopy (vec3_origin, ent->v.avelocity); } } // check for in water SV_CheckWaterTransition (ent); } /* =============================================================================== STEPPING MOVEMENT =============================================================================== */ /* ============= SV_Physics_Step Monsters freefall when they don't have a ground entity, otherwise all movement is done with discrete steps. This is also used for objects that have become still on the ground, but will fall if the floor is pulled out from under them. ============= */ void SV_Physics_Step (edict_t *ent) { qboolean hitsound; // freefall if not onground if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) { if (ent->v.velocity[2] < sv_gravity.value*-0.1) hitsound = true; else hitsound = false; SV_AddGravity (ent); SV_CheckVelocity (ent); SV_FlyMove (ent, host_frametime, NULL); SV_LinkEdict (ent, true); if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground { if (hitsound) SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); } } // regular thinking SV_RunThink (ent); SV_CheckWaterTransition (ent); } //============================================================================ /* ================ SV_Physics ================ */ void SV_Physics (void) { int i; int entity_cap; // For sv_freezenonclients edict_t *ent; // let the progs know that a new frame has started pr_global_struct->self = EDICT_TO_PROG(sv.edicts); pr_global_struct->other = EDICT_TO_PROG(sv.edicts); pr_global_struct->time = sv.time; PR_ExecuteProgram (pr_global_struct->StartFrame); //SV_CheckAllEnts (); // // treat each object in turn // ent = sv.edicts; if (sv_freezenonclients.value) entity_cap = svs.maxclients + 1; // Only run physics on clients and the world else entity_cap = sv.num_edicts; //for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent)) for (i=0 ; i<entity_cap ; i++, ent = NEXT_EDICT(ent)) { if (ent->free) continue; if (pr_global_struct->force_retouch) { SV_LinkEdict (ent, true); // force retouch even for stationary } if (i > 0 && i <= svs.maxclients) SV_Physics_Client (ent, i); else if (ent->v.movetype == MOVETYPE_PUSH) SV_Physics_Pusher (ent); else if (ent->v.movetype == MOVETYPE_NONE) SV_Physics_None (ent); else if (ent->v.movetype == MOVETYPE_NOCLIP) SV_Physics_Noclip (ent); else if (ent->v.movetype == MOVETYPE_STEP) SV_Physics_Step (ent); else if (ent->v.movetype == MOVETYPE_TOSS || ent->v.movetype == MOVETYPE_BOUNCE || ent->v.movetype == MOVETYPE_FLY || ent->v.movetype == MOVETYPE_FLYMISSILE) SV_Physics_Toss (ent); else Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype); } if (pr_global_struct->force_retouch) pr_global_struct->force_retouch--; if (!sv_freezenonclients.value) sv.time += host_frametime; } �����quakespasm-0.91.0/Quake/snd_flac.h������������������������������������������������������������������0000644�0000000�0000000�00000000317�12172764736�015461� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* fLaC streaming music support. */ #if !defined(_SND_FLAC_H_) #define _SND_FLAC_H_ 1 #if defined(USE_CODEC_FLAC) extern snd_codec_t flac_codec; #endif /* USE_CODEC_FLAC */ #endif /* ! _SND_FLAC_H_ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_codec.c�����������������������������������������������������������������0000644�0000000�0000000�00000014354�12220613364�015612� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Audio Codecs: Adapted from ioquake3 with changes. * For now, only handles streaming music, not sound effects. * * Copyright (C) 1999-2005 Id Software, Inc. * Copyright (C) 2005 Stuart Dalton <badcdev@gmail.com> * Copyright (C) 2010-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #include "quakedef.h" #include "snd_codec.h" #include "snd_codeci.h" /* headers for individual codecs */ #include "snd_mikmod.h" #include "snd_modplug.h" #include "snd_umx.h" #include "snd_wave.h" #include "snd_flac.h" #include "snd_mp3.h" #include "snd_vorbis.h" #include "snd_opus.h" static snd_codec_t *codecs; /* ================= S_CodecRegister ================= */ static void S_CodecRegister(snd_codec_t *codec) { codec->next = codecs; codecs = codec; } /* ================= S_CodecInit ================= */ void S_CodecInit (void) { snd_codec_t *codec; codecs = NULL; /* Register in the inverse order * of codec choice preference: */ #ifdef USE_CODEC_UMX S_CodecRegister(&umx_codec); #endif #ifdef USE_CODEC_MODPLUG S_CodecRegister(&modplug_codec); #endif #ifdef USE_CODEC_MIKMOD S_CodecRegister(&mikmod_codec); #endif #ifdef USE_CODEC_WAVE S_CodecRegister(&wav_codec); #endif #ifdef USE_CODEC_FLAC S_CodecRegister(&flac_codec); #endif #ifdef USE_CODEC_MP3 S_CodecRegister(&mp3_codec); #endif #ifdef USE_CODEC_VORBIS S_CodecRegister(&vorbis_codec); #endif #ifdef USE_CODEC_OPUS S_CodecRegister(&opus_codec); #endif codec = codecs; while (codec) { codec->initialize(); codec = codec->next; } } /* ================= S_CodecShutdown ================= */ void S_CodecShutdown (void) { snd_codec_t *codec = codecs; while (codec) { codec->shutdown(); codec = codec->next; } codecs = NULL; } /* ================= S_CodecOpenStream ================= */ snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type) { snd_codec_t *codec; snd_stream_t *stream; if (type == CODECTYPE_NONE) { Con_Printf("Bad type for %s\n", filename); return NULL; } codec = codecs; while (codec) { if (type == codec->type) break; codec = codec->next; } if (!codec) { Con_Printf("Unknown type for %s\n", filename); return NULL; } stream = S_CodecUtilOpen(filename, codec); if (stream) { if (codec->codec_open(stream)) stream->status = STREAM_PLAY; else S_CodecUtilClose(&stream); } return stream; } snd_stream_t *S_CodecOpenStreamExt (const char *filename) { snd_codec_t *codec; snd_stream_t *stream; const char *ext; ext = COM_FileGetExtension(filename); if (! *ext) { Con_Printf("No extension for %s\n", filename); return NULL; } codec = codecs; while (codec) { if (!q_strcasecmp(ext, codec->ext)) break; codec = codec->next; } if (!codec) { Con_Printf("Unknown extension for %s\n", filename); return NULL; } stream = S_CodecUtilOpen(filename, codec); if (stream) { if (codec->codec_open(stream)) stream->status = STREAM_PLAY; else S_CodecUtilClose(&stream); } return stream; } snd_stream_t *S_CodecOpenStreamAny (const char *filename) { snd_codec_t *codec; snd_stream_t *stream; const char *ext; ext = COM_FileGetExtension(filename); if (! *ext) /* try all available */ { char tmp[MAX_QPATH]; codec = codecs; while (codec) { q_snprintf(tmp, sizeof(tmp), "%s.%s", filename, codec->ext); stream = S_CodecUtilOpen(tmp, codec); if (stream) { if (codec->codec_open(stream)) { stream->status = STREAM_PLAY; return stream; } S_CodecUtilClose(&stream); } codec = codec->next; } return NULL; } else /* use the name as is */ { codec = codecs; while (codec) { if (!q_strcasecmp(ext, codec->ext)) break; codec = codec->next; } if (!codec) { Con_Printf("Unknown extension for %s\n", filename); return NULL; } stream = S_CodecUtilOpen(filename, codec); if (stream) { if (codec->codec_open(stream)) stream->status = STREAM_PLAY; else S_CodecUtilClose(&stream); } return stream; } } qboolean S_CodecForwardStream (snd_stream_t *stream, unsigned int type) { snd_codec_t *codec = codecs; while (codec) { if (type == codec->type) break; codec = codec->next; } if (!codec) return false; stream->codec = codec; return codec->codec_open(stream); } void S_CodecCloseStream (snd_stream_t *stream) { stream->status = STREAM_NONE; stream->codec->codec_close(stream); } int S_CodecRewindStream (snd_stream_t *stream) { return stream->codec->codec_rewind(stream); } int S_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) { return stream->codec->codec_read(stream, bytes, buffer); } /* Util functions (used by codecs) */ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec) { snd_stream_t *stream; FILE *handle; qboolean pak; long length; /* Try to open the file */ length = (long) COM_FOpenFile(filename, &handle, NULL); pak = file_from_pak; if (length == -1) { Con_DPrintf("Couldn't open %s\n", filename); return NULL; } /* Allocate a stream, Z_Malloc zeroes its content */ stream = (snd_stream_t *) Z_Malloc(sizeof(snd_stream_t)); stream->codec = codec; stream->fh.file = handle; stream->fh.start = ftell(handle); stream->fh.pos = 0; stream->fh.length = length; stream->fh.pak = stream->pak = pak; q_strlcpy(stream->name, filename, MAX_QPATH); return stream; } void S_CodecUtilClose(snd_stream_t **stream) { fclose((*stream)->fh.file); Z_Free(*stream); *stream = NULL; } int S_CodecIsAvailable (unsigned int type) { snd_codec_t *codec = codecs; while (codec) { if (type == codec->type) return codec->initialized; codec = codec->next; } return -1; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/Makefile.w32����������������������������������������������������������������0000644�0000000�0000000�00000013657�12513254455�015613� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# GNU Makefile for compiling Win32 quakespasm.exe using MinGW or MinGW-w64. # Usage: "make -f Makefile.w32" # To cross-compile on Linux hosts, see the "build_cross_win32*.sh" scripts. # "make DEBUG=1" to build a debug client. # "make SDL_CONFIG=/path/to/sdl-config" to override the locally included SDL versions. # "make WINSOCK2=1" to use WinSock2 api instead of old WinSock 1.1. ### Enable/disable SDL2 USE_SDL2=0 ### Enable/disable codecs for streaming music support USE_CODEC_WAVE=1 USE_CODEC_FLAC=1 USE_CODEC_MP3=1 USE_CODEC_VORBIS=1 USE_CODEC_OPUS=1 # either mikmod (preferred) or modplug, not both USE_CODEC_MIKMOD=1 USE_CODEC_MODPLUG=0 USE_CODEC_UMX=1 # which library to use for mp3 decoding: mad or mpg123 MP3LIB=mad # which library to use for ogg decoding: vorbis or tremor VORBISLIB=vorbis # --------------------------- # Helper functions # --------------------------- check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi;) # --------------------------- DEBUG ?= 0 WINSOCK2?= 0 # --------------------------- # build variables # --------------------------- CC = gcc LINKER = $(CC) WINDRES = windres STRIP = strip #CPUFLAGS= -mtune=i686 #CPUFLAGS= -march=pentium4 CPUFLAGS= LDFLAGS = DFLAGS ?= CFLAGS ?= -Wall -Wno-trigraphs CFLAGS += $(CPUFLAGS) ifneq ($(DEBUG),0) DFLAGS += -DDEBUG CFLAGS += -g do_strip= else DFLAGS += -DNDEBUG CFLAGS += -O2 CFLAGS += $(call check_gcc,-fweb,) CFLAGS += $(call check_gcc,-frename-registers,) cmd_strip=$(STRIP) $(1) define do_strip $(call cmd_strip,$(1)); endef endif ifeq ($(USE_SDL2),1) CFLAGS += -DUSE_SDL2 endif # default to our local SDL[2] for build ifeq ($(USE_SDL2),1) SDL_CONFIG ?=../Windows/SDL2/bin/sdl2-config --prefix=../Windows/SDL2 else SDL_CONFIG ?=../Windows/SDL/bin/sdl-config --prefix=../Windows/SDL endif SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags) SDL_LIBS := $(shell $(SDL_CONFIG) --libs) ifeq ($(WINSOCK2),1) DEFWINSOCK :=-D_USE_WINSOCK2 LIBWINSOCK := -lws2_32 else DEFWINSOCK := LIBWINSOCK := -lwsock32 endif CFLAGS += $(DEFWINSOCK) NET_LIBS := $(LIBWINSOCK) ifneq ($(VORBISLIB),vorbis) ifneq ($(VORBISLIB),tremor) $(error Invalid VORBISLIB setting) endif endif ifneq ($(MP3LIB),mpg123) ifneq ($(MP3LIB),mad) $(error Invalid MP3LIB setting) endif endif ifeq ($(MP3LIB),mad) mp3_obj=snd_mp3.o lib_mp3dec=-lmad endif ifeq ($(MP3LIB),mpg123) mp3_obj=snd_mpg123.o lib_mp3dec=-lmpg123 endif ifeq ($(VORBISLIB),vorbis) cpp_vorbisdec= lib_vorbisdec=-lvorbisfile -lvorbis -logg endif ifeq ($(VORBISLIB),tremor) cpp_vorbisdec=-DVORBIS_USE_TREMOR lib_vorbisdec=-lvorbisidec -logg endif CODECLIBS := ifeq ($(USE_CODEC_WAVE),1) CFLAGS+= -DUSE_CODEC_WAVE endif ifeq ($(USE_CODEC_FLAC),1) CFLAGS+= -DUSE_CODEC_FLAC CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x86 CODECLIBS+= -lFLAC endif ifeq ($(USE_CODEC_OPUS),1) CFLAGS+= -DUSE_CODEC_OPUS CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x86 CODECLIBS+= -lopusfile -lopus -logg endif ifeq ($(USE_CODEC_VORBIS),1) CFLAGS+= -DUSE_CODEC_VORBIS $(cpp_vorbisdec) CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x86 CODECLIBS+= $(lib_vorbisdec) endif ifeq ($(USE_CODEC_MP3),1) CFLAGS+= -DUSE_CODEC_MP3 CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x86 CODECLIBS+= $(lib_mp3dec) endif ifeq ($(USE_CODEC_MIKMOD),1) CFLAGS+= -DUSE_CODEC_MIKMOD CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x86 CODECLIBS+= -lmikmod endif ifeq ($(USE_CODEC_MODPLUG),1) CFLAGS+= -DUSE_CODEC_MODPLUG CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x86 CODECLIBS+= -lmodplug endif ifeq ($(USE_CODEC_UMX),1) CFLAGS+= -DUSE_CODEC_UMX endif CFLAGS+= $(CODEC_INC) COMMON_LIBS:= -lm -lopengl32 -lwinmm LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS) # --------------------------- # targets # --------------------------- .PHONY: clean debug release DEFAULT_TARGET := quakespasm.exe # --------------------------- # rules # --------------------------- %.o: %.c $(CC) $(DFLAGS) -c $(CFLAGS) $(SDL_CFLAGS) -o $@ $^ %.res: ../Windows/%.rc $(WINDRES) --output-format=coff -I../Windows -o $@ $^ # ---------------------------------------------------------------------------- # objects # ---------------------------------------------------------------------------- MUSIC_OBJS:= bgmusic.o \ snd_codec.o \ snd_flac.o \ snd_wave.o \ snd_vorbis.o \ snd_opus.o \ $(mp3_obj) \ snd_mikmod.o \ snd_modplug.o \ snd_umx.o COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS) SYSOBJ_SND := snd_sdl.o SYSOBJ_CDA := cd_sdl.o SYSOBJ_INPUT := in_sdl.o SYSOBJ_GL_VID:= gl_vidsdl.o SYSOBJ_NET := net_win.o net_wins.o net_wipx.o SYSOBJ_SYS := pl_win.o sys_sdl_win.o SYSOBJ_MAIN:= main_sdl.o SYSOBJ_RES := QuakeSpasm.res GLOBJS = \ gl_refrag.o \ gl_rlight.o \ gl_rmain.o \ gl_fog.o \ gl_rmisc.o \ r_part.o \ r_world.o \ gl_screen.o \ gl_sky.o \ gl_warp.o \ $(SYSOBJ_GL_VID) \ gl_draw.o \ image.o \ gl_texmgr.o \ gl_mesh.o \ r_sprite.o \ r_alias.o \ r_brush.o \ gl_model.o OBJS := strlcat.o \ strlcpy.o \ $(GLOBJS) \ $(SYSOBJ_INPUT) \ $(COMOBJ_SND) \ $(SYSOBJ_SND) \ $(SYSOBJ_CDA) \ $(SYSOBJ_NET) \ net_dgrm.o \ net_loop.o \ net_main.o \ chase.o \ cl_demo.o \ cl_input.o \ cl_main.o \ cl_parse.o \ cl_tent.o \ console.o \ keys.o \ menu.o \ sbar.o \ view.o \ wad.o \ cmd.o \ common.o \ crc.o \ cvar.o \ cfgfile.o \ host.o \ host_cmd.o \ mathlib.o \ pr_cmds.o \ pr_edict.o \ pr_exec.o \ sv_main.o \ sv_move.o \ sv_phys.o \ sv_user.o \ world.o \ zone.o \ $(SYSOBJ_SYS) $(SYSOBJ_MAIN) $(SYSOBJ_RES) # ------------------------ # MinGW build rules # ------------------------ quakespasm.exe: $(OBJS) $(LINKER) $(OBJS) $(LDFLAGS) $(LIBS) $(SDL_LIBS) -o $@ $(call do_strip,$@) release: quakespasm.exe debug: $(error Use "make DEBUG=1") clean: rm -f $(shell find . \( -name '*~' -o -name '#*#' -o -name '*.o' -o -name '*.res' -o -name $(DEFAULT_TARGET) \) -print) ���������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cfgfile.c�������������������������������������������������������������������0000644�0000000�0000000�00000007410�12407762022�015266� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * cfgfile.c -- misc reads from the config file * * Copyright (C) 2008-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #include "quakedef.h" static fshandle_t *cfg_file; /* =================== CFG_ReadCvars used for doing early reads from config.cfg searching the list of given cvar names for the user-set values. a temporary solution until we merge a better cvar system. the num_vars argument must be the exact number of strings in the array, otherwise I have nothing against going out of bounds. =================== */ void CFG_ReadCvars (const char **vars, int num_vars) { char buff[1024], *tmp; int i, j; if (!cfg_file || num_vars < 1) return; j = 0; do { i = 0; memset (buff, 0, sizeof(buff)); // we expect a line in the format that Cvar_WriteVariables // writes to the config file. although I'm trying to be as // much cautious as possible, if the user screws it up by // editing it, it's his fault. if (FS_fgets(buff, sizeof(buff), cfg_file)) { // remove end-of-line characters while (buff[i]) { if (buff[i] == '\r' || buff[i] == '\n') buff[i] = '\0'; // while we're here, replace tabs with spaces if (buff[i] == '\t') buff[i] = ' '; i++; } // go to the last character while (buff[i] == 0 && i > 0) i--; // remove trailing spaces while (i > 0) { if (buff[i] == ' ') { buff[i] = '\0'; i--; } else break; } // the line must end with a quotation mark if (buff[i] != '\"') continue; buff[i] = '\0'; for (i = 0; i < num_vars && vars[i]; i++) { // look for the cvar name + one space tmp = strstr(buff, va("%s ",vars[i])); if (tmp != buff) continue; // locate the first quotation mark tmp = strchr(buff, '\"'); if (tmp) { Cvar_Set (vars[i], tmp + 1); j++; break; } } } if (j == num_vars) break; } while (!FS_feof(cfg_file) && !FS_ferror(cfg_file)); FS_rewind (cfg_file); } /* =================== CFG_ReadCvarOverrides convenience function, reading the "+" command line override values of cvars in the given list. doesn't do anything with the config file. =================== */ void CFG_ReadCvarOverrides (const char **vars, int num_vars) { char buff[64]; int i, j; if (num_vars < 1) return; buff[0] = '+'; for (i = 0; i < num_vars; i++) { q_strlcpy (&buff[1], vars[i], sizeof(buff) - 1); j = COM_CheckParm(buff); if (j != 0 && j < com_argc - 1) { if (com_argv[j + 1][0] != '-' && com_argv[j + 1][0] != '+') Cvar_Set(vars[i], com_argv[j + 1]); } } } void CFG_CloseConfig (void) { if (cfg_file) { FS_fclose(cfg_file); Z_Free(cfg_file); cfg_file = NULL; } } int CFG_OpenConfig (const char *cfg_name) { FILE *f; long length; qboolean pak; CFG_CloseConfig (); length = (long) COM_FOpenFile (cfg_name, &f, NULL); pak = file_from_pak; if (length == -1) return -1; cfg_file = (fshandle_t *) Z_Malloc(sizeof(fshandle_t)); cfg_file->file = f; cfg_file->start = ftell(f); cfg_file->pos = 0; cfg_file->length = length; cfg_file->pak = pak; return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/progs.h���������������������������������������������������������������������0000644�0000000�0000000�00000007752�12407762022�015037� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_PROGS_H #define _QUAKE_PROGS_H #include "pr_comp.h" /* defs shared with qcc */ #include "progdefs.h" /* generated by program cdefs */ typedef union eval_s { string_t string; float _float; float vector[3]; func_t function; int _int; int edict; } eval_t; #define MAX_ENT_LEAFS 32 typedef struct edict_s { qboolean free; link_t area; /* linked to a division node or leaf */ int num_leafs; int leafnums[MAX_ENT_LEAFS]; entity_state_t baseline; unsigned char alpha; /* johnfitz -- hack to support alpha since it's not part of entvars_t */ qboolean sendinterval; /* johnfitz -- send time until nextthink to client for better lerp timing */ float freetime; /* sv.time when the object was freed */ entvars_t v; /* C exported fields from progs */ /* other fields from progs come immediately after */ } edict_t; #define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area) //============================================================================ extern dprograms_t *progs; extern dfunction_t *pr_functions; extern dstatement_t *pr_statements; extern globalvars_t *pr_global_struct; extern float *pr_globals; /* same as pr_global_struct */ extern int pr_edict_size; /* in bytes */ void PR_Init (void); void PR_ExecuteProgram (func_t fnum); void PR_LoadProgs (void); const char *PR_GetString (int num); int PR_SetEngineString (const char *s); int PR_AllocString (int bufferlength, char **ptr); void PR_Profile_f (void); edict_t *ED_Alloc (void); void ED_Free (edict_t *ed); void ED_Print (edict_t *ed); void ED_Write (FILE *f, edict_t *ed); const char *ED_ParseEdict (const char *data, edict_t *ent); void ED_WriteGlobals (FILE *f); void ED_ParseGlobals (const char *data); void ED_LoadFromFile (const char *data); /* #define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size)) #define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts) / pr_edict_size) */ edict_t *EDICT_NUM(int n); int NUM_FOR_EDICT(edict_t *e); #define NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size)) #define EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts) #define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e)) #define G_FLOAT(o) (pr_globals[o]) #define G_INT(o) (*(int *)&pr_globals[o]) #define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o])) #define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o)) #define G_VECTOR(o) (&pr_globals[o]) #define G_STRING(o) (PR_GetString(*(string_t *)&pr_globals[o])) #define G_FUNCTION(o) (*(func_t *)&pr_globals[o]) #define E_FLOAT(e,o) (((float*)&e->v)[o]) #define E_INT(e,o) (*(int *)&((float*)&e->v)[o]) #define E_VECTOR(e,o) (&((float*)&e->v)[o]) #define E_STRING(e,o) (PR_GetString(*(string_t *)&((float*)&e->v)[o])) extern int type_size[8]; typedef void (*builtin_t) (void); extern builtin_t *pr_builtins; extern int pr_numbuiltins; extern int pr_argc; extern qboolean pr_trace; extern dfunction_t *pr_xfunction; extern int pr_xstatement; extern unsigned short pr_crc; void PR_RunError (const char *error, ...) __attribute__((__format__(__printf__,1,2), __noreturn__)); void ED_PrintEdicts (void); void ED_PrintNum (int ent); eval_t *GetEdictFieldValue(edict_t *ed, const char *field); #endif /* _QUAKE_PROGS_H */ ����������������������quakespasm-0.91.0/Quake/net_win.c�������������������������������������������������������������������0000644�0000000�0000000�00000005033�12407762022�015331� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "q_stdinc.h" #include "arch_def.h" #include "net_sys.h" #include "quakedef.h" #include "net_defs.h" #include "net_dgrm.h" #include "net_loop.h" net_driver_t net_drivers[] = { { "Loopback", false, Loop_Init, Loop_Listen, Loop_SearchForHosts, Loop_Connect, Loop_CheckNewConnections, Loop_GetMessage, Loop_SendMessage, Loop_SendUnreliableMessage, Loop_CanSendMessage, Loop_CanSendUnreliableMessage, Loop_Close, Loop_Shutdown }, { "Datagram", false, Datagram_Init, Datagram_Listen, Datagram_SearchForHosts, Datagram_Connect, Datagram_CheckNewConnections, Datagram_GetMessage, Datagram_SendMessage, Datagram_SendUnreliableMessage, Datagram_CanSendMessage, Datagram_CanSendUnreliableMessage, Datagram_Close, Datagram_Shutdown } }; const int net_numdrivers = (sizeof(net_drivers) / sizeof(net_drivers[0])); #include "net_wins.h" #include "net_wipx.h" net_landriver_t net_landrivers[] = { { "Winsock TCPIP", false, 0, WINS_Init, WINS_Shutdown, WINS_Listen, WINS_OpenSocket, WINS_CloseSocket, WINS_Connect, WINS_CheckNewConnections, WINS_Read, WINS_Write, WINS_Broadcast, WINS_AddrToString, WINS_StringToAddr, WINS_GetSocketAddr, WINS_GetNameFromAddr, WINS_GetAddrFromName, WINS_AddrCompare, WINS_GetSocketPort, WINS_SetSocketPort }, { "Winsock IPX", false, 0, WIPX_Init, WIPX_Shutdown, WIPX_Listen, WIPX_OpenSocket, WIPX_CloseSocket, WIPX_Connect, WIPX_CheckNewConnections, WIPX_Read, WIPX_Write, WIPX_Broadcast, WIPX_AddrToString, WIPX_StringToAddr, WIPX_GetSocketAddr, WIPX_GetNameFromAddr, WIPX_GetAddrFromName, WIPX_AddrCompare, WIPX_GetSocketPort, WIPX_SetSocketPort } }; const int net_numlandrivers = (sizeof(net_landrivers) / sizeof(net_landrivers[0])); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_mikmod.h����������������������������������������������������������������0000644�0000000�0000000�00000000353�12220541170�016007� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* module tracker decoding support using libmikmod */ #if !defined(_SND_MIKMOD_H_) #define _SND_MIKMOD_H_ #if defined(USE_CODEC_MIKMOD) extern snd_codec_t mikmod_codec; #endif /* USE_CODEC_MIKMOD */ #endif /* ! _SND_MIKMOD_H_ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/r_world.c�������������������������������������������������������������������0000644�0000000�0000000�00000071506�12555253135�015352� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // r_world.c: world model rendering #include "quakedef.h" extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater, r_oldskyleaf, r_showtris; //johnfitz extern glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; byte *SV_FatPVS (vec3_t org, qmodel_t *worldmodel); extern byte mod_novis[MAX_MAP_LEAFS/8]; int vis_changed; //if true, force pvs to be refreshed //============================================================================== // // SETUP CHAINS // //============================================================================== /* ================ R_ClearTextureChains -- ericw clears texture chains for all textures used by the given model, and also clears the lightmap chains ================ */ void R_ClearTextureChains (qmodel_t *mod, texchain_t chain) { int i; // set all chains to null for (i=0 ; i<mod->numtextures ; i++) if (mod->textures[i]) mod->textures[i]->texturechains[chain] = NULL; // clear lightmap chains memset (lightmap_polys, 0, sizeof(lightmap_polys)); } /* ================ R_ChainSurface -- ericw -- adds the given surface to its texture chain ================ */ void R_ChainSurface (msurface_t *surf, texchain_t chain) { surf->texturechain = surf->texinfo->texture->texturechains[chain]; surf->texinfo->texture->texturechains[chain] = surf; } /* =============== R_MarkSurfaces -- johnfitz -- mark surfaces based on PVS and rebuild texture chains =============== */ void R_MarkSurfaces (void) { byte *vis; mleaf_t *leaf; mnode_t *node; msurface_t *surf, **mark; int i, j; qboolean nearwaterportal; // clear lightmap chains memset (lightmap_polys, 0, sizeof(lightmap_polys)); // check this leaf for water portals // TODO: loop through all water surfs and use distance to leaf cullbox nearwaterportal = false; for (i=0, mark = r_viewleaf->firstmarksurface; i < r_viewleaf->nummarksurfaces; i++, mark++) if ((*mark)->flags & SURF_DRAWTURB) nearwaterportal = true; // choose vis data if (r_novis.value || r_viewleaf->contents == CONTENTS_SOLID || r_viewleaf->contents == CONTENTS_SKY) vis = &mod_novis[0]; else if (nearwaterportal) vis = SV_FatPVS (r_origin, cl.worldmodel); else vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel); // if surface chains don't need regenerating, just add static entities and return if (r_oldviewleaf == r_viewleaf && !vis_changed && !nearwaterportal) { leaf = &cl.worldmodel->leafs[1]; for (i=0 ; i<cl.worldmodel->numleafs ; i++, leaf++) if (vis[i>>3] & (1<<(i&7))) if (leaf->efrags) R_StoreEfrags (&leaf->efrags); return; } vis_changed = false; r_visframecount++; r_oldviewleaf = r_viewleaf; // iterate through leaves, marking surfaces leaf = &cl.worldmodel->leafs[1]; for (i=0 ; i<cl.worldmodel->numleafs ; i++, leaf++) { if (vis[i>>3] & (1<<(i&7))) { if (r_oldskyleaf.value || leaf->contents != CONTENTS_SKY) for (j=0, mark = leaf->firstmarksurface; j<leaf->nummarksurfaces; j++, mark++) (*mark)->visframe = r_visframecount; // add static models if (leaf->efrags) R_StoreEfrags (&leaf->efrags); } } // set all chains to null for (i=0 ; i<cl.worldmodel->numtextures ; i++) if (cl.worldmodel->textures[i]) cl.worldmodel->textures[i]->texturechains[chain_world] = NULL; // rebuild chains #if 1 //iterate through surfaces one node at a time to rebuild chains //need to do it this way if we want to work with tyrann's skip removal tool //becuase his tool doesn't actually remove the surfaces from the bsp surfaces lump //nor does it remove references to them in each leaf's marksurfaces list for (i=0, node = cl.worldmodel->nodes ; i<cl.worldmodel->numnodes ; i++, node++) for (j=0, surf=&cl.worldmodel->surfaces[node->firstsurface] ; j<node->numsurfaces ; j++, surf++) if (surf->visframe == r_visframecount) { R_ChainSurface(surf, chain_world); } #else //the old way surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface]; for (i=0 ; i<cl.worldmodel->nummodelsurfaces ; i++, surf++) { if (surf->visframe == r_visframecount) { R_ChainSurface(surf, chain_world); } } #endif } /* ================ R_BackFaceCull -- johnfitz -- returns true if the surface is facing away from vieworg ================ */ qboolean R_BackFaceCull (msurface_t *surf) { double dot; switch (surf->plane->type) { case PLANE_X: dot = r_refdef.vieworg[0] - surf->plane->dist; break; case PLANE_Y: dot = r_refdef.vieworg[1] - surf->plane->dist; break; case PLANE_Z: dot = r_refdef.vieworg[2] - surf->plane->dist; break; default: dot = DotProduct (r_refdef.vieworg, surf->plane->normal) - surf->plane->dist; break; } if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) return true; return false; } /* ================ R_CullSurfaces -- johnfitz ================ */ void R_CullSurfaces (void) { msurface_t *s; int i; texture_t *t; if (!r_drawworld_cheatsafe) return; // ericw -- instead of testing (s->visframe == r_visframecount) on all world // surfaces, use the chained surfaces, which is exactly the same set of sufaces for (i=0 ; i<cl.worldmodel->numtextures ; i++) { t = cl.worldmodel->textures[i]; if (!t || !t->texturechains[chain_world]) continue; for (s = t->texturechains[chain_world]; s; s = s->texturechain) { if (R_CullBox(s->mins, s->maxs) || R_BackFaceCull (s)) s->culled = true; else { s->culled = false; rs_brushpolys++; //count wpolys here if (s->texinfo->texture->warpimage) s->texinfo->texture->update_warp = true; } } } } /* ================ R_BuildLightmapChains -- johnfitz -- used for r_lightmap 1 ericw -- now always used at the start of R_DrawTextureChains for the mh dynamic lighting speedup ================ */ void R_BuildLightmapChains (qmodel_t *model, texchain_t chain) { texture_t *t; msurface_t *s; int i; // clear lightmap chains (already done in r_marksurfaces, but clearing them here to be safe becuase of r_stereo) memset (lightmap_polys, 0, sizeof(lightmap_polys)); // now rebuild them for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain]) continue; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) R_RenderDynamicLightmaps (s); } } //============================================================================== // // DRAW CHAINS // //============================================================================== /* ============= R_BeginTransparentDrawing -- ericw ============= */ static void R_BeginTransparentDrawing (float entalpha) { if (entalpha < 1.0f) { glDepthMask (GL_FALSE); glEnable (GL_BLEND); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f (1,1,1,entalpha); } } /* ============= R_EndTransparentDrawing -- ericw ============= */ static void R_EndTransparentDrawing (float entalpha) { if (entalpha < 1.0f) { glDepthMask (GL_TRUE); glDisable (GL_BLEND); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3f (1, 1, 1); } } /* ================ R_DrawTextureChains_ShowTris -- johnfitz ================ */ void R_DrawTextureChains_ShowTris (qmodel_t *model, texchain_t chain) { int i; msurface_t *s; texture_t *t; glpoly_t *p; for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t) continue; if (r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB)) { for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) for (p = s->polys->next; p; p = p->next) { DrawGLTriangleFan (p); } } else { for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { DrawGLTriangleFan (s->polys); } } } } /* ================ R_DrawTextureChains_Drawflat -- johnfitz ================ */ void R_DrawTextureChains_Drawflat (qmodel_t *model, texchain_t chain) { int i; msurface_t *s; texture_t *t; glpoly_t *p; for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t) continue; if (r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB)) { for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) for (p = s->polys->next; p; p = p->next) { srand((unsigned int) (uintptr_t) p); glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); DrawGLPoly (p); rs_brushpasses++; } } else { for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { srand((unsigned int) (uintptr_t) s->polys); glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); DrawGLPoly (s->polys); rs_brushpasses++; } } } glColor3f (1,1,1); srand ((int) (cl.time * 1000)); } /* ================ R_DrawTextureChains_Glow -- johnfitz ================ */ void R_DrawTextureChains_Glow (qmodel_t *model, entity_t *ent, texchain_t chain) { int i; msurface_t *s; texture_t *t; gltexture_t *glt; qboolean bound; for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain] || !(glt = R_TextureAnimation(t, ent != NULL ? ent->frame : 0)->fullbright)) continue; bound = false; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { GL_Bind (glt); bound = true; } DrawGLPoly (s->polys); rs_brushpasses++; } } } //============================================================================== // // VBO SUPPORT // //============================================================================== static unsigned int R_NumTriangleIndicesForSurf (msurface_t *s) { return 3 * (s->numedges - 2); } /* ================ R_TriangleIndicesForSurf Writes out the triangle indices needed to draw s as a triangle list. The number of indices it will write is given by R_NumTriangleIndicesForSurf. ================ */ static void R_TriangleIndicesForSurf (msurface_t *s, unsigned int *dest) { int i; for (i=2; i<s->numedges; i++) { *dest++ = s->vbo_firstvert; *dest++ = s->vbo_firstvert + i - 1; *dest++ = s->vbo_firstvert + i; } } #define MAX_BATCH_SIZE 4096 static unsigned int vbo_indices[MAX_BATCH_SIZE]; static unsigned int num_vbo_indices; /* ================ R_ClearBatch ================ */ static void R_ClearBatch () { num_vbo_indices = 0; } /* ================ R_FlushBatch Draw the current batch if non-empty and clears it, ready for more R_BatchSurface calls. ================ */ static void R_FlushBatch () { if (num_vbo_indices > 0) { glDrawElements (GL_TRIANGLES, num_vbo_indices, GL_UNSIGNED_INT, vbo_indices); num_vbo_indices = 0; } } /* ================ R_BatchSurface Add the surface to the current batch, or just draw it immediately if we're not using VBOs. ================ */ static void R_BatchSurface (msurface_t *s) { int num_surf_indices; num_surf_indices = R_NumTriangleIndicesForSurf (s); if (num_vbo_indices + num_surf_indices > MAX_BATCH_SIZE) R_FlushBatch(); R_TriangleIndicesForSurf (s, &vbo_indices[num_vbo_indices]); num_vbo_indices += num_surf_indices; } /* ================ R_DrawTextureChains_Multitexture -- johnfitz ================ */ void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_t chain) { int i, j; msurface_t *s; texture_t *t; float *v; qboolean bound; for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE)) continue; bound = false; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { GL_Bind ((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture); if (t->texturechains[chain]->flags & SURF_DRAWFENCE) glEnable (GL_ALPHA_TEST); // Flip alpha test back on GL_EnableMultitexture(); // selects TEXTURE1 bound = true; } GL_Bind (lightmap_textures[s->lightmaptexturenum]); glBegin(GL_POLYGON); v = s->polys->verts[0]; for (j=0 ; j<s->polys->numverts ; j++, v+= VERTEXSIZE) { GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]); GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]); glVertex3fv (v); } glEnd (); rs_brushpasses++; } GL_DisableMultitexture(); // selects TEXTURE0 if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE) glDisable (GL_ALPHA_TEST); // Flip alpha test back off } } /* ================ R_DrawTextureChains_NoTexture -- johnfitz draws surfs whose textures were missing from the BSP ================ */ void R_DrawTextureChains_NoTexture (qmodel_t *model, texchain_t chain) { int i; msurface_t *s; texture_t *t; qboolean bound; for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_NOTEXTURE)) continue; bound = false; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { GL_Bind (t->gltexture); bound = true; } DrawGLPoly (s->polys); rs_brushpasses++; } } } /* ================ R_DrawTextureChains_TextureOnly -- johnfitz ================ */ void R_DrawTextureChains_TextureOnly (qmodel_t *model, entity_t *ent, texchain_t chain) { int i; msurface_t *s; texture_t *t; qboolean bound; for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) continue; bound = false; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { GL_Bind ((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture); if (t->texturechains[chain]->flags & SURF_DRAWFENCE) glEnable (GL_ALPHA_TEST); // Flip alpha test back on bound = true; } DrawGLPoly (s->polys); rs_brushpasses++; } if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE) glDisable (GL_ALPHA_TEST); // Flip alpha test back off } } /* ================ GL_WaterAlphaForEntitySurface -- ericw Returns the water alpha to use for the entity and surface combination. ================ */ float GL_WaterAlphaForEntitySurface (entity_t *ent, msurface_t *s) { float entalpha; if (ent == NULL || ent->alpha == ENTALPHA_DEFAULT) entalpha = GL_WaterAlphaForSurface(s); else entalpha = ENTALPHA_DECODE(ent->alpha); return entalpha; } /* ================ R_DrawTextureChains_Water -- johnfitz ================ */ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain) { int i; msurface_t *s; texture_t *t; glpoly_t *p; qboolean bound; float entalpha; if (r_drawflat_cheatsafe || r_lightmap_cheatsafe) // ericw -- !r_drawworld_cheatsafe check moved to R_DrawWorld_Water () return; if (r_oldwater.value) { for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTURB)) continue; bound = false; entalpha = 1.0f; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { entalpha = GL_WaterAlphaForEntitySurface (ent, s); R_BeginTransparentDrawing (entalpha); GL_Bind (t->gltexture); bound = true; } for (p = s->polys->next; p; p = p->next) { DrawWaterPoly (p); rs_brushpasses++; } } R_EndTransparentDrawing (entalpha); } } else { for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTURB)) continue; bound = false; entalpha = 1.0f; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { entalpha = GL_WaterAlphaForEntitySurface (ent, s); R_BeginTransparentDrawing (entalpha); GL_Bind (t->warpimage); if (model != cl.worldmodel) { // ericw -- this is copied from R_DrawSequentialPoly. // If the poly is not part of the world we have to // set this flag t->update_warp = true; // FIXME: one frame too late! } bound = true; } DrawGLPoly (s->polys); rs_brushpasses++; } R_EndTransparentDrawing (entalpha); } } } /* ================ R_DrawTextureChains_White -- johnfitz -- draw sky and water as white polys when r_lightmap is 1 ================ */ void R_DrawTextureChains_White (qmodel_t *model, texchain_t chain) { int i; msurface_t *s; texture_t *t; glDisable (GL_TEXTURE_2D); for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTILED)) continue; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { DrawGLPoly (s->polys); rs_brushpasses++; } } glEnable (GL_TEXTURE_2D); } /* ================ R_DrawLightmapChains -- johnfitz -- R_BlendLightmaps stripped down to almost nothing ================ */ void R_DrawLightmapChains (void) { int i, j; glpoly_t *p; float *v; for (i=0 ; i<MAX_LIGHTMAPS ; i++) { if (!lightmap_polys[i]) continue; GL_Bind (lightmap_textures[i]); for (p = lightmap_polys[i]; p; p=p->chain) { glBegin (GL_POLYGON); v = p->verts[0]; for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE) { glTexCoord2f (v[5], v[6]); glVertex3fv (v); } glEnd (); rs_brushpasses++; } } } extern GLuint gl_bmodel_vbo; /* ================ R_DrawTextureChains_Multitexture_VBO -- ericw Draw lightmapped surfaces with fulbrights in one pass, using VBO. Requires 3 TMUs, GL_COMBINE_EXT, and GL_ADD. ================ */ void R_DrawTextureChains_Multitexture_VBO (qmodel_t *model, entity_t *ent, texchain_t chain) { int i; msurface_t *s; texture_t *t; qboolean bound; int lastlightmap; gltexture_t *fullbright = NULL; // Bind the buffers GL_BindBuffer (GL_ARRAY_BUFFER, gl_bmodel_vbo); GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); // indices come from client memory! // Setup vertex array pointers glVertexPointer (3, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0)); glEnableClientState (GL_VERTEX_ARRAY); GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB); glTexCoordPointer (2, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0) + 3); glEnableClientState (GL_TEXTURE_COORD_ARRAY); GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB); glTexCoordPointer (2, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0) + 5); glEnableClientState (GL_TEXTURE_COORD_ARRAY); // TMU 2 is for fullbrights; same texture coordinates as TMU 0 GL_ClientActiveTextureFunc (GL_TEXTURE2_ARB); glTexCoordPointer (2, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0) + 3); glEnableClientState (GL_TEXTURE_COORD_ARRAY); // Setup TMU 1 (lightmap) GL_SelectTexture (GL_TEXTURE1_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, gl_overbright.value ? 2.0f : 1.0f); glEnable(GL_TEXTURE_2D); // Setup TMU 2 (fullbrights) GL_SelectTexture (GL_TEXTURE2_ARB); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); for (i=0 ; i<model->numtextures ; i++) { t = model->textures[i]; if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE)) continue; // Enable/disable TMU 2 (fullbrights) GL_SelectTexture (GL_TEXTURE2_ARB); if (gl_fullbrights.value && (fullbright = R_TextureAnimation(t, ent != NULL ? ent->frame : 0)->fullbright)) { glEnable(GL_TEXTURE_2D); GL_Bind (fullbright); } else glDisable(GL_TEXTURE_2D); R_ClearBatch (); bound = false; lastlightmap = 0; // avoid compiler warning for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { GL_SelectTexture (GL_TEXTURE0_ARB); GL_Bind ((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture); if (t->texturechains[chain]->flags & SURF_DRAWFENCE) glEnable (GL_ALPHA_TEST); // Flip alpha test back on bound = true; lastlightmap = s->lightmaptexturenum; } if (s->lightmaptexturenum != lastlightmap) R_FlushBatch (); GL_SelectTexture (GL_TEXTURE1_ARB); GL_Bind (lightmap_textures[s->lightmaptexturenum]); lastlightmap = s->lightmaptexturenum; R_BatchSurface (s); rs_brushpasses++; } R_FlushBatch (); if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE) glDisable (GL_ALPHA_TEST); // Flip alpha test back off } // Reset TMU states GL_SelectTexture (GL_TEXTURE2_ARB); glDisable (GL_TEXTURE_2D); GL_SelectTexture (GL_TEXTURE1_ARB); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glDisable (GL_TEXTURE_2D); GL_SelectTexture (GL_TEXTURE0_ARB); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Disable client state glDisableClientState (GL_VERTEX_ARRAY); GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB); glDisableClientState (GL_TEXTURE_COORD_ARRAY); GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB); glDisableClientState (GL_TEXTURE_COORD_ARRAY); GL_ClientActiveTextureFunc (GL_TEXTURE2_ARB); glDisableClientState (GL_TEXTURE_COORD_ARRAY); } /* ============= R_DrawWorld -- johnfitz -- rewritten ============= */ void R_DrawTextureChains (qmodel_t *model, entity_t *ent, texchain_t chain) { float entalpha; if (ent != NULL) entalpha = ENTALPHA_DECODE(ent->alpha); else entalpha = 1; // ericw -- the mh dynamic lightmap speedup: make a first pass through all // surfaces we are going to draw, and rebuild any lightmaps that need it. // this also chains surfaces by lightmap which is used by r_lightmap 1. // the previous implementation of the speedup uploaded lightmaps one frame // late which was visible under some conditions, this method avoids that. R_BuildLightmapChains (model, chain); R_UploadLightmaps (); if (r_drawflat_cheatsafe) { glDisable (GL_TEXTURE_2D); R_DrawTextureChains_Drawflat (model, chain); glEnable (GL_TEXTURE_2D); return; } if (r_fullbright_cheatsafe) { R_BeginTransparentDrawing (entalpha); R_DrawTextureChains_TextureOnly (model, ent, chain); R_EndTransparentDrawing (entalpha); goto fullbrights; } if (r_lightmap_cheatsafe) { if (!gl_overbright.value) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(0.5, 0.5, 0.5); } R_DrawLightmapChains (); if (!gl_overbright.value) { glColor3f(1,1,1); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } R_DrawTextureChains_White (model, chain); return; } R_BeginTransparentDrawing (entalpha); R_DrawTextureChains_NoTexture (model, chain); if (gl_vbo_able && gl_texture_env_combine && gl_texture_env_add && gl_mtexable && gl_max_texture_units >= 3) { R_DrawTextureChains_Multitexture_VBO (model, ent, chain); R_EndTransparentDrawing (entalpha); return; } if (gl_overbright.value) { if (gl_texture_env_combine && gl_mtexable) //case 1: texture and lightmap in one pass, overbright using texture combiners { GL_EnableMultitexture (); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); GL_DisableMultitexture (); R_DrawTextureChains_Multitexture (model, ent, chain); GL_EnableMultitexture (); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DisableMultitexture (); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else if (entalpha < 1) //case 2: can't do multipass if entity has alpha, so just draw the texture { R_DrawTextureChains_TextureOnly (model, ent, chain); } else //case 3: texture in one pass, lightmap in second pass using 2x modulation blend func, fog in third pass { //to make fog work with multipass lightmapping, need to do one pass //with no fog, one modulate pass with black fog, and one additive //pass with black geometry and normal fog Fog_DisableGFog (); R_DrawTextureChains_TextureOnly (model, ent, chain); Fog_EnableGFog (); glDepthMask (GL_FALSE); glEnable (GL_BLEND); glBlendFunc (GL_DST_COLOR, GL_SRC_COLOR); //2x modulate Fog_StartAdditive (); R_DrawLightmapChains (); Fog_StopAdditive (); if (Fog_GetDensity() > 0) { glBlendFunc(GL_ONE, GL_ONE); //add glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(0,0,0); R_DrawTextureChains_TextureOnly (model, ent, chain); glColor3f(1,1,1); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable (GL_BLEND); glDepthMask (GL_TRUE); } } else { if (gl_mtexable) //case 4: texture and lightmap in one pass, regular modulation { GL_EnableMultitexture (); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DisableMultitexture (); R_DrawTextureChains_Multitexture (model, ent, chain); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } else if (entalpha < 1) //case 5: can't do multipass if entity has alpha, so just draw the texture { R_DrawTextureChains_TextureOnly (model, ent, chain); } else //case 6: texture in one pass, lightmap in a second pass, fog in third pass { //to make fog work with multipass lightmapping, need to do one pass //with no fog, one modulate pass with black fog, and one additive //pass with black geometry and normal fog Fog_DisableGFog (); R_DrawTextureChains_TextureOnly (model, ent, chain); Fog_EnableGFog (); glDepthMask (GL_FALSE); glEnable (GL_BLEND); glBlendFunc(GL_ZERO, GL_SRC_COLOR); //modulate Fog_StartAdditive (); R_DrawLightmapChains (); Fog_StopAdditive (); if (Fog_GetDensity() > 0) { glBlendFunc(GL_ONE, GL_ONE); //add glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(0,0,0); R_DrawTextureChains_TextureOnly (model, ent, chain); glColor3f(1,1,1); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable (GL_BLEND); glDepthMask (GL_TRUE); } } R_EndTransparentDrawing (entalpha); fullbrights: if (gl_fullbrights.value) { glDepthMask (GL_FALSE); glEnable (GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f (entalpha, entalpha, entalpha); Fog_StartAdditive (); R_DrawTextureChains_Glow (model, ent, chain); Fog_StopAdditive (); glColor3f (1, 1, 1); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable (GL_BLEND); glDepthMask (GL_TRUE); } } /* ============= R_DrawWorld -- ericw -- moved from R_DrawTextureChains, which is no longer specific to the world. ============= */ void R_DrawWorld (void) { if (!r_drawworld_cheatsafe) return; R_DrawTextureChains (cl.worldmodel, NULL, chain_world); } /* ============= R_DrawWorld_Water -- ericw -- moved from R_DrawTextureChains_Water, which is no longer specific to the world. ============= */ void R_DrawWorld_Water (void) { if (!r_drawworld_cheatsafe) return; R_DrawTextureChains_Water (cl.worldmodel, NULL, chain_world); } /* ============= R_DrawWorld_ShowTris -- ericw -- moved from R_DrawTextureChains_ShowTris, which is no longer specific to the world. ============= */ void R_DrawWorld_ShowTris (void) { if (!r_drawworld_cheatsafe) return; R_DrawTextureChains_ShowTris (cl.worldmodel, chain_world); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cl_demo.c�������������������������������������������������������������������0000644�0000000�0000000�00000025447�12532220152�015273� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" static void CL_FinishTimeDemo (void); /* ============================================================================== DEMO CODE When a demo is playing back, all NET_SendMessages are skipped, and NET_GetMessages are read from the demo file. Whenever cl.time gets past the last received message, another message is read from the demo file. ============================================================================== */ // from ProQuake: space to fill out the demo header for record at any time static byte demo_head[3][MAX_MSGLEN]; static int demo_head_size[2]; /* ============== CL_StopPlayback Called when a demo file runs out, or the user starts a game ============== */ void CL_StopPlayback (void) { if (!cls.demoplayback) return; fclose (cls.demofile); cls.demoplayback = false; cls.demopaused = false; cls.demofile = NULL; cls.state = ca_disconnected; if (cls.timedemo) CL_FinishTimeDemo (); } /* ==================== CL_WriteDemoMessage Dumps the current net message, prefixed by the length and view angles ==================== */ static void CL_WriteDemoMessage (void) { int len; int i; float f; len = LittleLong (net_message.cursize); fwrite (&len, 4, 1, cls.demofile); for (i = 0; i < 3; i++) { f = LittleFloat (cl.viewangles[i]); fwrite (&f, 4, 1, cls.demofile); } fwrite (net_message.data, net_message.cursize, 1, cls.demofile); fflush (cls.demofile); } static int CL_GetDemoMessage (void) { int r, i; float f; if (cls.demopaused) return 0; // decide if it is time to grab the next message if (cls.signon == SIGNONS) // always grab until fully connected { if (cls.timedemo) { if (host_framecount == cls.td_lastframe) return 0; // already read this frame's message cls.td_lastframe = host_framecount; // if this is the second frame, grab the real td_starttime // so the bogus time on the first frame doesn't count if (host_framecount == cls.td_startframe + 1) cls.td_starttime = realtime; } else if (/* cl.time > 0 && */ cl.time <= cl.mtime[0]) { return 0; // don't need another message yet } } // get the next message fread (&net_message.cursize, 4, 1, cls.demofile); VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); for (i = 0 ; i < 3 ; i++) { r = fread (&f, 4, 1, cls.demofile); cl.mviewangles[0][i] = LittleFloat (f); } net_message.cursize = LittleLong (net_message.cursize); if (net_message.cursize > MAX_MSGLEN) Sys_Error ("Demo message > MAX_MSGLEN"); r = fread (net_message.data, net_message.cursize, 1, cls.demofile); if (r != 1) { CL_StopPlayback (); return 0; } return 1; } /* ==================== CL_GetMessage Handles recording and playback of demos, on top of NET_ code ==================== */ int CL_GetMessage (void) { int r; if (cls.demoplayback) return CL_GetDemoMessage (); while (1) { r = NET_GetMessage (cls.netcon); if (r != 1 && r != 2) return r; // discard nop keepalive message if (net_message.cursize == 1 && net_message.data[0] == svc_nop) Con_Printf ("<-- server to client keepalive\n"); else break; } if (cls.demorecording) CL_WriteDemoMessage (); if (cls.signon < 2) { // record messages before full connection, so that a // demo record can happen after connection is done memcpy(demo_head[cls.signon], net_message.data, net_message.cursize); demo_head_size[cls.signon] = net_message.cursize; } return r; } /* ==================== CL_Stop_f stop recording a demo ==================== */ void CL_Stop_f (void) { if (cmd_source != src_command) return; if (!cls.demorecording) { Con_Printf ("Not recording a demo.\n"); return; } // write a disconnect message to the demo file SZ_Clear (&net_message); MSG_WriteByte (&net_message, svc_disconnect); CL_WriteDemoMessage (); // finish up fclose (cls.demofile); cls.demofile = NULL; cls.demorecording = false; Con_Printf ("Completed demo\n"); // ericw -- update demo tab-completion list DemoList_Rebuild (); } /* ==================== CL_Record_f record <demoname> <map> [cd track] ==================== */ void CL_Record_f (void) { int c; char name[MAX_OSPATH]; int track; if (cmd_source != src_command) return; if (cls.demoplayback) { Con_Printf ("Can't record during demo playback\n"); return; } if (cls.demorecording) CL_Stop_f(); c = Cmd_Argc(); if (c != 2 && c != 3 && c != 4) { Con_Printf ("record <demoname> [<map> [cd track]]\n"); return; } if (strstr(Cmd_Argv(1), "..")) { Con_Printf ("Relative pathnames are not allowed.\n"); return; } if (c == 2 && cls.state == ca_connected) { #if 0 Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); return; #endif if (cls.signon < 2) { Con_Printf("Can't record - try again when connected\n"); return; } } // write the forced cd track number, or -1 if (c == 4) { track = atoi(Cmd_Argv(3)); Con_Printf ("Forcing CD track to %i\n", cls.forcetrack); } else { track = -1; } q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1)); // start the map up if (c > 2) { Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command); if (cls.state != ca_connected) return; } // open the demo file COM_AddExtension (name, ".dem", sizeof(name)); Con_Printf ("recording to %s.\n", name); cls.demofile = fopen (name, "wb"); if (!cls.demofile) { Con_Printf ("ERROR: couldn't create %s\n", name); return; } cls.forcetrack = track; fprintf (cls.demofile, "%i\n", cls.forcetrack); cls.demorecording = true; // from ProQuake: initialize the demo file if we're already connected if (c == 2 && cls.state == ca_connected) { byte *data = net_message.data; int cursize = net_message.cursize; int i; for (i = 0; i < 2; i++) { net_message.data = demo_head[i]; net_message.cursize = demo_head_size[i]; CL_WriteDemoMessage(); } net_message.data = demo_head[2]; SZ_Clear (&net_message); // current names, colors, and frag counts for (i = 0; i < cl.maxclients; i++) { MSG_WriteByte (&net_message, svc_updatename); MSG_WriteByte (&net_message, i); MSG_WriteString (&net_message, cl.scores[i].name); MSG_WriteByte (&net_message, svc_updatefrags); MSG_WriteByte (&net_message, i); MSG_WriteShort (&net_message, cl.scores[i].frags); MSG_WriteByte (&net_message, svc_updatecolors); MSG_WriteByte (&net_message, i); MSG_WriteByte (&net_message, cl.scores[i].colors); } // send all current light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { MSG_WriteByte (&net_message, svc_lightstyle); MSG_WriteByte (&net_message, i); MSG_WriteString (&net_message, cl_lightstyle[i].map); } // what about the CD track or SVC fog... future consideration. MSG_WriteByte (&net_message, svc_updatestat); MSG_WriteByte (&net_message, STAT_TOTALSECRETS); MSG_WriteLong (&net_message, cl.stats[STAT_TOTALSECRETS]); MSG_WriteByte (&net_message, svc_updatestat); MSG_WriteByte (&net_message, STAT_TOTALMONSTERS); MSG_WriteLong (&net_message, cl.stats[STAT_TOTALMONSTERS]); MSG_WriteByte (&net_message, svc_updatestat); MSG_WriteByte (&net_message, STAT_SECRETS); MSG_WriteLong (&net_message, cl.stats[STAT_SECRETS]); MSG_WriteByte (&net_message, svc_updatestat); MSG_WriteByte (&net_message, STAT_MONSTERS); MSG_WriteLong (&net_message, cl.stats[STAT_MONSTERS]); // view entity MSG_WriteByte (&net_message, svc_setview); MSG_WriteShort (&net_message, cl.viewentity); // signon MSG_WriteByte (&net_message, svc_signonnum); MSG_WriteByte (&net_message, 3); CL_WriteDemoMessage(); // restore net_message net_message.data = data; net_message.cursize = cursize; } } /* ==================== CL_PlayDemo_f play [demoname] ==================== */ void CL_PlayDemo_f (void) { char name[MAX_OSPATH]; int i, c; qboolean neg; if (cmd_source != src_command) return; if (Cmd_Argc() != 2) { Con_Printf ("playdemo <demoname> : plays a demo\n"); return; } // disconnect from server CL_Disconnect (); // open the demo file q_strlcpy (name, Cmd_Argv(1), sizeof(name)); COM_AddExtension (name, ".dem", sizeof(name)); Con_Printf ("Playing demo from %s.\n", name); COM_FOpenFile (name, &cls.demofile, NULL); if (!cls.demofile) { Con_Printf ("ERROR: couldn't open %s\n", name); cls.demonum = -1; // stop demo loop return; } // ZOID, fscanf is evil // O.S.: if a space character e.g. 0x20 (' ') follows '\n', // fscanf skips that byte too and screws up further reads. // fscanf (cls.demofile, "%i\n", &cls.forcetrack); cls.forcetrack = 0; neg = false; // read a decimal integer possibly with a leading '-', // followed by a '\n': for (i = 0; i < 13; i++) { c = getc(cls.demofile); if (c == '\n') break; if (c == '-') { neg = true; continue; } // check for multiple '-' or legal digits? meh... cls.forcetrack = cls.forcetrack * 10 + (c - '0'); } if (c != '\n') { fclose (cls.demofile); cls.demofile = NULL; cls.demonum = -1; // stop demo loop Con_Printf ("ERROR: demo \"%s\" is invalid\n", name); return; } if (neg) cls.forcetrack = -cls.forcetrack; cls.demoplayback = true; cls.demopaused = false; cls.state = ca_connected; // get rid of the menu and/or console key_dest = key_game; } /* ==================== CL_FinishTimeDemo ==================== */ static void CL_FinishTimeDemo (void) { int frames; float time; cls.timedemo = false; // the first frame didn't count frames = (host_framecount - cls.td_startframe) - 1; time = realtime - cls.td_starttime; if (!time) time = 1; Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time); } /* ==================== CL_TimeDemo_f timedemo [demoname] ==================== */ void CL_TimeDemo_f (void) { if (cmd_source != src_command) return; if (Cmd_Argc() != 2) { Con_Printf ("timedemo <demoname> : gets demo speeds\n"); return; } CL_PlayDemo_f (); if (!cls.demofile) return; // cls.td_starttime will be grabbed at the second frame of the demo, so // all the loading time doesn't get counted cls.timedemo = true; cls.td_startframe = host_framecount; cls.td_lastframe = -1; // get a new message this frame } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/pl_win.c��������������������������������������������������������������������0000644�0000000�0000000�00000005326�12407762022�015163� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #include <windows.h> #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #include <SDL2/SDL_syswm.h> #else #include <SDL/SDL.h> #include <SDL/SDL_syswm.h> #endif #else #include "SDL.h" #include "SDL_syswm.h" #endif static HICON icon; void PL_SetWindowIcon (void) { HINSTANCE handle; SDL_SysWMinfo wminfo; HWND hwnd; handle = GetModuleHandle(NULL); icon = LoadIcon(handle, "icon"); if (!icon) return; /* no icon in the exe */ SDL_VERSION(&wminfo.version); #if defined(USE_SDL2) if (SDL_GetWindowWMInfo((SDL_Window*) VID_GetWindow(), &wminfo) != SDL_TRUE) return; /* wrong SDL version */ hwnd = wminfo.info.win.window; #else if (SDL_GetWMInfo(&wminfo) != 1) return; /* wrong SDL version */ hwnd = wminfo.window; #endif #ifdef _WIN64 SetClassLongPtr(hwnd, GCLP_HICON, (LONG_PTR) icon); #else SetClassLong(hwnd, GCL_HICON, (LONG) icon); #endif } void PL_VID_Shutdown (void) { DestroyIcon(icon); } #define MAX_CLIPBOARDTXT MAXCMDLINE /* 256 */ char *PL_GetClipboardData (void) { char *data = NULL; char *cliptext; if (OpenClipboard(NULL) != 0) { HANDLE hClipboardData; if ((hClipboardData = GetClipboardData(CF_TEXT)) != NULL) { cliptext = (char *) GlobalLock(hClipboardData); if (cliptext != NULL) { size_t size = GlobalSize(hClipboardData) + 1; /* this is intended for simple small text copies * such as an ip address, etc: do chop the size * here, otherwise we may experience Z_Malloc() * failures and all other not-oh-so-fun stuff. */ size = q_min(MAX_CLIPBOARDTXT, size); data = (char *) Z_Malloc(size); q_strlcpy (data, cliptext, size); GlobalUnlock (hClipboardData); } } CloseClipboard (); } return data; } void PL_ErrorDialog(const char *errorMsg) { MessageBox (NULL, errorMsg, "Quake Error", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/progdefs.h������������������������������������������������������������������0000644�0000000�0000000�00000001553�11340073704�015504� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __PROGDEFS_H #define __PROGDEFS_H #include "progdefs.q1" #endif /* __PROGDEFS_H */ �����������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/vid.h�����������������������������������������������������������������������0000644�0000000�0000000�00000004721�12407762022�014460� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __VID_DEFS_H #define __VID_DEFS_H // vid.h -- video driver defs #define VID_CBITS 6 #define VID_GRADES (1 << VID_CBITS) #define GAMMA_MAX 3.0 // moved here for global use -- kristian typedef enum { MS_UNINIT, MS_WINDOWED, MS_FULLSCREEN } modestate_t; extern modestate_t modestate; // a pixel can be one, two, or four bytes typedef byte pixel_t; typedef struct vrect_s { int x, y, width, height; struct vrect_s *pnext; } vrect_t; typedef struct { pixel_t *buffer; // invisible buffer pixel_t *colormap; // 256 * VID_GRADES size unsigned short *colormap16; // 256 * VID_GRADES size int fullbright; // index of first fullbright color int rowbytes; // may be > width if displayed in a window int width; int height; float aspect; // width / height -- < 0 is taller than wide int numpages; int recalc_refdef; // if true, recalc vid-based stuff pixel_t *conbuffer; int conrowbytes; int conwidth; int conheight; int maxwarpwidth; int maxwarpheight; pixel_t *direct; // direct drawing to framebuffer, if not NULL } viddef_t; extern viddef_t vid; // global video state extern void (*vid_menudrawfn)(void); extern void (*vid_menukeyfn)(int key); extern void (*vid_menucmdfn)(void); //johnfitz void VID_Init (void); //johnfitz -- removed palette from argument list void VID_Shutdown (void); // Called at shutdown void VID_Update (vrect_t *rects); // flushes the given rectangles from the view buffer to the screen void VID_SyncCvars (void); void VID_Toggle (void); void *VID_GetWindow (void); qboolean VID_HasMouseOrInputFocus (void); qboolean VID_IsMinimized (void); #endif /* __VID_DEFS_H */ �����������������������������������������������quakespasm-0.91.0/Quake/net_wins.h������������������������������������������������������������������0000644�0000000�0000000�00000003556�12407762022�015531� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __NET_WINSOCK_H #define __NET_WINSOCK_H sys_socket_t WINS_Init (void); void WINS_Shutdown (void); void WINS_Listen (qboolean state); sys_socket_t WINS_OpenSocket (int port); int WINS_CloseSocket (sys_socket_t socketid); int WINS_Connect (sys_socket_t socketid, struct qsockaddr *addr); sys_socket_t WINS_CheckNewConnections (void); int WINS_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr); int WINS_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr); int WINS_Broadcast (sys_socket_t socketid, byte *buf, int len); const char *WINS_AddrToString (struct qsockaddr *addr); int WINS_StringToAddr (const char *string, struct qsockaddr *addr); int WINS_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr); int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name); int WINS_GetAddrFromName (const char *name, struct qsockaddr *addr); int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); int WINS_GetSocketPort (struct qsockaddr *addr); int WINS_SetSocketPort (struct qsockaddr *addr, int port); #endif /* __NET_WINSOCK_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/strlcpy.c�������������������������������������������������������������������0000644�0000000�0000000�00000003064�11676323013�015370� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/types.h> #include <string.h> #include "strl_fn.h" /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t q_strlcpy (char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_bsd.c�������������������������������������������������������������������0000644�0000000�0000000�00000004146�12407762022�015310� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "q_stdinc.h" #include "arch_def.h" #include "net_sys.h" #include "quakedef.h" #include "net_defs.h" #include "net_dgrm.h" #include "net_loop.h" net_driver_t net_drivers[] = { { "Loopback", false, Loop_Init, Loop_Listen, Loop_SearchForHosts, Loop_Connect, Loop_CheckNewConnections, Loop_GetMessage, Loop_SendMessage, Loop_SendUnreliableMessage, Loop_CanSendMessage, Loop_CanSendUnreliableMessage, Loop_Close, Loop_Shutdown }, { "Datagram", false, Datagram_Init, Datagram_Listen, Datagram_SearchForHosts, Datagram_Connect, Datagram_CheckNewConnections, Datagram_GetMessage, Datagram_SendMessage, Datagram_SendUnreliableMessage, Datagram_CanSendMessage, Datagram_CanSendUnreliableMessage, Datagram_Close, Datagram_Shutdown } }; const int net_numdrivers = (sizeof(net_drivers) / sizeof(net_drivers[0])); #include "net_udp.h" net_landriver_t net_landrivers[] = { { "UDP", false, 0, UDP_Init, UDP_Shutdown, UDP_Listen, UDP_OpenSocket, UDP_CloseSocket, UDP_Connect, UDP_CheckNewConnections, UDP_Read, UDP_Write, UDP_Broadcast, UDP_AddrToString, UDP_StringToAddr, UDP_GetSocketAddr, UDP_GetNameFromAddr, UDP_GetAddrFromName, UDP_AddrCompare, UDP_GetSocketPort, UDP_SetSocketPort } }; const int net_numlandrivers = (sizeof(net_landrivers) / sizeof(net_landrivers[0])); ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/draw.h����������������������������������������������������������������������0000644�0000000�0000000�00000003343�12407762022�014632� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_DRAW_H #define _QUAKE_DRAW_H // draw.h -- these are the only functions outside the refresh allowed // to touch the vid buffer extern qpic_t *draw_disc; // also used on sbar void Draw_Init (void); void Draw_Character (int x, int y, int num); void Draw_DebugChar (char num); void Draw_Pic (int x, int y, qpic_t *pic); void Draw_TransPicTranslate (int x, int y, qpic_t *pic, int top, int bottom); //johnfitz -- more parameters void Draw_ConsoleBackground (void); //johnfitz -- removed parameter int lines void Draw_TileClear (int x, int y, int w, int h); void Draw_Fill (int x, int y, int w, int h, int c, float alpha); //johnfitz -- added alpha void Draw_FadeScreen (void); void Draw_String (int x, int y, const char *str); qpic_t *Draw_PicFromWad (const char *name); qpic_t *Draw_CachePic (const char *path); void Draw_NewGame (void); void GL_SetCanvas (canvastype newcanvas); //johnfitz #endif /* _QUAKE_DRAW_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/keys.c����������������������������������������������������������������������0000644�0000000�0000000�00000054772�12417527670�014670� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #include "arch_def.h" /* key up events are sent even if in console mode */ #define HISTORY_FILE_NAME "history.txt" #define CMDLINES 32 char key_lines[CMDLINES][MAXCMDLINE]; int key_linepos; int key_insert; //johnfitz -- insert key toggle (for editing) double key_blinktime; //johnfitz -- fudge cursor blinking to make it easier to spot in certain cases int edit_line = 0; int history_line = 0; keydest_t key_dest; #define MAX_KEYS 256 char *keybindings[MAX_KEYS]; qboolean consolekeys[MAX_KEYS]; // if true, can't be rebound while in console qboolean menubound[MAX_KEYS]; // if true, can't be rebound while in menu qboolean keydown[MAX_KEYS]; typedef struct { const char *name; int keynum; } keyname_t; keyname_t keynames[] = { {"TAB", K_TAB}, {"ENTER", K_ENTER}, {"ESCAPE", K_ESCAPE}, {"SPACE", K_SPACE}, {"BACKSPACE", K_BACKSPACE}, {"UPARROW", K_UPARROW}, {"DOWNARROW", K_DOWNARROW}, {"LEFTARROW", K_LEFTARROW}, {"RIGHTARROW", K_RIGHTARROW}, {"ALT", K_ALT}, {"CTRL", K_CTRL}, {"SHIFT", K_SHIFT}, // {"KP_NUMLOCK", K_KP_NUMLOCK}, {"KP_SLASH", K_KP_SLASH}, {"KP_STAR", K_KP_STAR}, {"KP_MINUS", K_KP_MINUS}, {"KP_HOME", K_KP_HOME}, {"KP_UPARROW", K_KP_UPARROW}, {"KP_PGUP", K_KP_PGUP}, {"KP_PLUS", K_KP_PLUS}, {"KP_LEFTARROW", K_KP_LEFTARROW}, {"KP_5", K_KP_5}, {"KP_RIGHTARROW", K_KP_RIGHTARROW}, {"KP_END", K_KP_END}, {"KP_DOWNARROW", K_KP_DOWNARROW}, {"KP_PGDN", K_KP_PGDN}, {"KP_ENTER", K_KP_ENTER}, {"KP_INS", K_KP_INS}, {"KP_DEL", K_KP_DEL}, {"F1", K_F1}, {"F2", K_F2}, {"F3", K_F3}, {"F4", K_F4}, {"F5", K_F5}, {"F6", K_F6}, {"F7", K_F7}, {"F8", K_F8}, {"F9", K_F9}, {"F10", K_F10}, {"F11", K_F11}, {"F12", K_F12}, {"INS", K_INS}, {"DEL", K_DEL}, {"PGDN", K_PGDN}, {"PGUP", K_PGUP}, {"HOME", K_HOME}, {"END", K_END}, {"COMMAND", K_COMMAND}, {"MOUSE1", K_MOUSE1}, {"MOUSE2", K_MOUSE2}, {"MOUSE3", K_MOUSE3}, {"MOUSE4", K_MOUSE4}, {"MOUSE5", K_MOUSE5}, {"JOY1", K_JOY1}, {"JOY2", K_JOY2}, {"JOY3", K_JOY3}, {"JOY4", K_JOY4}, {"AUX1", K_AUX1}, {"AUX2", K_AUX2}, {"AUX3", K_AUX3}, {"AUX4", K_AUX4}, {"AUX5", K_AUX5}, {"AUX6", K_AUX6}, {"AUX7", K_AUX7}, {"AUX8", K_AUX8}, {"AUX9", K_AUX9}, {"AUX10", K_AUX10}, {"AUX11", K_AUX11}, {"AUX12", K_AUX12}, {"AUX13", K_AUX13}, {"AUX14", K_AUX14}, {"AUX15", K_AUX15}, {"AUX16", K_AUX16}, {"AUX17", K_AUX17}, {"AUX18", K_AUX18}, {"AUX19", K_AUX19}, {"AUX20", K_AUX20}, {"AUX21", K_AUX21}, {"AUX22", K_AUX22}, {"AUX23", K_AUX23}, {"AUX24", K_AUX24}, {"AUX25", K_AUX25}, {"AUX26", K_AUX26}, {"AUX27", K_AUX27}, {"AUX28", K_AUX28}, {"AUX29", K_AUX29}, {"AUX30", K_AUX30}, {"AUX31", K_AUX31}, {"AUX32", K_AUX32}, {"PAUSE", K_PAUSE}, {"MWHEELUP", K_MWHEELUP}, {"MWHEELDOWN", K_MWHEELDOWN}, {"SEMICOLON", ';'}, // because a raw semicolon seperates commands {"BACKQUOTE", '`'}, // because a raw backquote may toggle the console {"TILDE", '~'}, // because a raw tilde may toggle the console {NULL, 0} }; /* ============================================================================== LINE TYPING INTO THE CONSOLE ============================================================================== */ static void PasteToConsole (void) { char *cbd, *p, *workline; int mvlen, inslen; if (key_linepos == MAXCMDLINE - 1) return; if ((cbd = PL_GetClipboardData()) == NULL) return; p = cbd; while (*p) { if (*p == '\n' || *p == '\r' || *p == '\b') { *p = 0; break; } p++; } inslen = (int) (p - cbd); if (inslen + key_linepos > MAXCMDLINE - 1) inslen = MAXCMDLINE - 1 - key_linepos; if (inslen <= 0) goto done; workline = key_lines[edit_line]; workline += key_linepos; mvlen = (int) strlen(workline); if (mvlen + inslen + key_linepos > MAXCMDLINE - 1) { mvlen = MAXCMDLINE - 1 - key_linepos - inslen; if (mvlen < 0) mvlen = 0; } // insert the string if (mvlen != 0) memmove (workline + inslen, workline, mvlen); memcpy (workline, cbd, inslen); key_linepos += inslen; workline[mvlen + inslen] = '\0'; done: Z_Free(cbd); } /* ==================== Key_Console -- johnfitz -- heavy revision Interactive line editing and console scrollback ==================== */ extern char *con_text, key_tabpartial[MAXCMDLINE]; extern int con_current, con_linewidth, con_vislines; void Key_Console (int key) { static char current[MAXCMDLINE] = ""; int history_line_last; size_t len; char *workline = key_lines[edit_line]; switch (key) { case K_ENTER: case K_KP_ENTER: key_tabpartial[0] = 0; Cbuf_AddText (workline + 1); // skip the prompt Cbuf_AddText ("\n"); Con_Printf ("%s\n", workline); // If the last two lines are identical, skip storing this line in history // by not incrementing edit_line if (strcmp(workline, key_lines[(edit_line-1)&31])) edit_line = (edit_line + 1) & 31; history_line = edit_line; key_lines[edit_line][0] = ']'; key_lines[edit_line][1] = 0; //johnfitz -- otherwise old history items show up in the new edit line key_linepos = 1; if (cls.state == ca_disconnected) SCR_UpdateScreen (); // force an update, because the command may take some time return; case K_TAB: Con_TabComplete (); return; case K_BACKSPACE: key_tabpartial[0] = 0; if (key_linepos > 1) { workline += key_linepos - 1; if (workline[1]) { len = strlen(workline); memmove (workline, workline + 1, len); } else *workline = 0; key_linepos--; } return; case K_DEL: key_tabpartial[0] = 0; workline += key_linepos; if (*workline) { if (workline[1]) { len = strlen(workline); memmove (workline, workline + 1, len); } else *workline = 0; } return; case K_HOME: if (keydown[K_CTRL]) { //skip initial empty lines int i, x; char *line; for (i = con_current - con_totallines + 1; i <= con_current; i++) { line = con_text + (i % con_totallines) * con_linewidth; for (x = 0; x < con_linewidth; x++) { if (line[x] != ' ') break; } if (x != con_linewidth) break; } con_backscroll = CLAMP(0, con_current-i%con_totallines-2, con_totallines-(glheight>>3)-1); } else key_linepos = 1; return; case K_END: if (keydown[K_CTRL]) con_backscroll = 0; else key_linepos = strlen(workline); return; case K_PGUP: case K_MWHEELUP: con_backscroll += keydown[K_CTRL] ? ((con_vislines>>3) - 4) : 2; if (con_backscroll > con_totallines - (vid.height>>3) - 1) con_backscroll = con_totallines - (vid.height>>3) - 1; return; case K_PGDN: case K_MWHEELDOWN: con_backscroll -= keydown[K_CTRL] ? ((con_vislines>>3) - 4) : 2; if (con_backscroll < 0) con_backscroll = 0; return; case K_LEFTARROW: if (key_linepos > 1) { key_linepos--; key_blinktime = realtime; } return; case K_RIGHTARROW: len = strlen(workline); if ((int)len == key_linepos) { len = strlen(key_lines[(edit_line + 31) & 31]); if ((int)len <= key_linepos) return; // no character to get workline += key_linepos; *workline = key_lines[(edit_line + 31) & 31][key_linepos]; workline[1] = 0; key_linepos++; } else { key_linepos++; key_blinktime = realtime; } return; case K_UPARROW: if (history_line == edit_line) Q_strcpy(current, workline); history_line_last = history_line; do { history_line = (history_line - 1) & 31; } while (history_line != edit_line && !key_lines[history_line][1]); if (history_line == edit_line) { history_line = history_line_last; return; } key_tabpartial[0] = 0; Q_strcpy(workline, key_lines[history_line]); key_linepos = Q_strlen(workline); return; case K_DOWNARROW: if (history_line == edit_line) return; key_tabpartial[0] = 0; do { history_line = (history_line + 1) & 31; } while (history_line != edit_line && !key_lines[history_line][1]); if (history_line == edit_line) Q_strcpy(workline, current); else Q_strcpy(workline, key_lines[history_line]); key_linepos = Q_strlen(workline); return; case K_INS: if (keydown[K_SHIFT]) /* Shift-Ins paste */ PasteToConsole(); else key_insert ^= 1; return; case 'v': case 'V': #if defined(PLATFORM_OSX) || defined(PLATFORM_MAC) if (keydown[K_COMMAND]) { /* Cmd+v paste (Mac-only) */ PasteToConsole(); return; } #endif if (keydown[K_CTRL]) { /* Ctrl+v paste */ PasteToConsole(); return; } break; case 'c': case 'C': if (keydown[K_CTRL]) { /* Ctrl+C: abort the line -- S.A */ Con_Printf ("%s\n", workline); workline[0] = ']'; workline[1] = 0; key_linepos = 1; history_line= edit_line; return; } break; } } void Char_Console (int key) { size_t len; char *workline = key_lines[edit_line]; if (key_linepos < MAXCMDLINE-1) { qboolean endpos = !workline[key_linepos]; key_tabpartial[0] = 0; //johnfitz // if inserting, move the text to the right if (key_insert && !endpos) { workline[MAXCMDLINE - 2] = 0; workline += key_linepos; len = strlen(workline) + 1; memmove (workline + 1, workline, len); *workline = key; } else { workline += key_linepos; *workline = key; // null terminate if at the end if (endpos) workline[1] = 0; } key_linepos++; } } //============================================================================ qboolean chat_team = false; static char chat_buffer[MAXCMDLINE]; static int chat_bufferlen = 0; const char *Key_GetChatBuffer (void) { return chat_buffer; } int Key_GetChatMsgLen (void) { return chat_bufferlen; } void Key_EndChat (void) { key_dest = key_game; chat_bufferlen = 0; chat_buffer[0] = 0; } void Key_Message (int key) { switch (key) { case K_ENTER: case K_KP_ENTER: if (chat_team) Cbuf_AddText ("say_team \""); else Cbuf_AddText ("say \""); Cbuf_AddText(chat_buffer); Cbuf_AddText("\"\n"); Key_EndChat (); return; case K_ESCAPE: Key_EndChat (); return; case K_BACKSPACE: if (chat_bufferlen) chat_buffer[--chat_bufferlen] = 0; return; } } void Char_Message (int key) { if (chat_bufferlen == sizeof(chat_buffer) - 1) return; // all full chat_buffer[chat_bufferlen++] = key; chat_buffer[chat_bufferlen] = 0; } //============================================================================ /* =================== Key_StringToKeynum Returns a key number to be used to index keybindings[] by looking at the given string. Single ascii characters return themselves, while the K_* names are matched up. =================== */ int Key_StringToKeynum (const char *str) { keyname_t *kn; if (!str || !str[0]) return -1; if (!str[1]) return str[0]; for (kn=keynames ; kn->name ; kn++) { if (!q_strcasecmp(str,kn->name)) return kn->keynum; } return -1; } /* =================== Key_KeynumToString Returns a string (either a single ascii char, or a K_* name) for the given keynum. FIXME: handle quote special (general escape sequence?) =================== */ const char *Key_KeynumToString (int keynum) { static char tinystr[2]; keyname_t *kn; if (keynum == -1) return "<KEY NOT FOUND>"; if (keynum > 32 && keynum < 127) { // printable ascii tinystr[0] = keynum; tinystr[1] = 0; return tinystr; } for (kn = keynames; kn->name; kn++) { if (keynum == kn->keynum) return kn->name; } return "<UNKNOWN KEYNUM>"; } /* =================== Key_SetBinding =================== */ void Key_SetBinding (int keynum, const char *binding) { if (keynum == -1) return; // free old bindings if (keybindings[keynum]) { Z_Free (keybindings[keynum]); keybindings[keynum] = NULL; } // allocate memory for new binding if (binding) keybindings[keynum] = Z_Strdup(binding); } /* =================== Key_Unbind_f =================== */ void Key_Unbind_f (void) { int b; if (Cmd_Argc() != 2) { Con_Printf ("unbind <key> : remove commands from a key\n"); return; } b = Key_StringToKeynum (Cmd_Argv(1)); if (b == -1) { Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); return; } Key_SetBinding (b, NULL); } void Key_Unbindall_f (void) { int i; for (i = 0; i < MAX_KEYS; i++) { if (keybindings[i]) Key_SetBinding (i, NULL); } } /* ============ Key_Bindlist_f -- johnfitz ============ */ void Key_Bindlist_f (void) { int i, count; count = 0; for (i = 0; i < MAX_KEYS; i++) { if (keybindings[i] && *keybindings[i]) { Con_SafePrintf (" %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]); count++; } } Con_SafePrintf ("%i bindings\n", count); } /* =================== Key_Bind_f =================== */ void Key_Bind_f (void) { int i, c, b; char cmd[1024]; c = Cmd_Argc(); if (c != 2 && c != 3) { Con_Printf ("bind <key> [command] : attach a command to a key\n"); return; } b = Key_StringToKeynum (Cmd_Argv(1)); if (b == -1) { Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); return; } if (c == 2) { if (keybindings[b]) Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] ); else Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) ); return; } // copy the rest of the command line cmd[0] = 0; for (i = 2; i < c; i++) { q_strlcat (cmd, Cmd_Argv(i), sizeof(cmd)); if (i != (c-1)) q_strlcat (cmd, " ", sizeof(cmd)); } Key_SetBinding (b, cmd); } /* ============ Key_WriteBindings Writes lines containing "bind key value" ============ */ void Key_WriteBindings (FILE *f) { int i; // unbindall before loading stored bindings: if (cfg_unbindall.value) fprintf (f, "unbindall\n"); for (i = 0; i < MAX_KEYS; i++) { if (keybindings[i] && *keybindings[i]) fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]); } } void History_Init (void) { int i, c; FILE *hf; for (i = 0; i < CMDLINES; i++) { key_lines[i][0] = ']'; key_lines[i][1] = 0; } key_linepos = 1; hf = fopen(va("%s/%s", host_parms->userdir, HISTORY_FILE_NAME), "rt"); if (hf != NULL) { do { i = 1; do { c = fgetc(hf); key_lines[edit_line][i++] = c; } while (c != '\r' && c != '\n' && c != EOF && i < MAXCMDLINE); key_lines[edit_line][i - 1] = 0; edit_line = (edit_line + 1) & (CMDLINES - 1); /* for people using a windows-generated history file on unix: */ if (c == '\r' || c == '\n') { do c = fgetc(hf); while (c == '\r' || c == '\n'); if (c != EOF) ungetc(c, hf); else c = 0; /* loop once more, otherwise last line is lost */ } } while (c != EOF && edit_line < CMDLINES); fclose(hf); history_line = edit_line = (edit_line - 1) & (CMDLINES - 1); key_lines[edit_line][0] = ']'; key_lines[edit_line][1] = 0; } } void History_Shutdown (void) { int i; FILE *hf; hf = fopen(va("%s/%s", host_parms->userdir, HISTORY_FILE_NAME), "wt"); if (hf != NULL) { i = edit_line; do { i = (i + 1) & (CMDLINES - 1); } while (i != edit_line && !key_lines[i][1]); while (i != edit_line && key_lines[i][1]) { fprintf(hf, "%s\n", key_lines[i] + 1); i = (i + 1) & (CMDLINES - 1); } fclose(hf); } } /* =================== Key_Init =================== */ void Key_Init (void) { int i; History_Init (); key_blinktime = realtime; //johnfitz // // initialize consolekeys[] // for (i = 32; i < 127; i++) // ascii characters consolekeys[i] = true; consolekeys['`'] = false; consolekeys['~'] = false; consolekeys[K_TAB] = true; consolekeys[K_ENTER] = true; consolekeys[K_ESCAPE] = true; consolekeys[K_BACKSPACE] = true; consolekeys[K_UPARROW] = true; consolekeys[K_DOWNARROW] = true; consolekeys[K_LEFTARROW] = true; consolekeys[K_RIGHTARROW] = true; consolekeys[K_CTRL] = true; consolekeys[K_SHIFT] = true; consolekeys[K_INS] = true; consolekeys[K_DEL] = true; consolekeys[K_PGDN] = true; consolekeys[K_PGUP] = true; consolekeys[K_HOME] = true; consolekeys[K_END] = true; consolekeys[K_KP_NUMLOCK] = true; consolekeys[K_KP_SLASH] = true; consolekeys[K_KP_STAR] = true; consolekeys[K_KP_MINUS] = true; consolekeys[K_KP_HOME] = true; consolekeys[K_KP_UPARROW] = true; consolekeys[K_KP_PGUP] = true; consolekeys[K_KP_PLUS] = true; consolekeys[K_KP_LEFTARROW] = true; consolekeys[K_KP_5] = true; consolekeys[K_KP_RIGHTARROW] = true; consolekeys[K_KP_END] = true; consolekeys[K_KP_DOWNARROW] = true; consolekeys[K_KP_PGDN] = true; consolekeys[K_KP_ENTER] = true; consolekeys[K_KP_INS] = true; consolekeys[K_KP_DEL] = true; #if defined(PLATFORM_OSX) || defined(PLATFORM_MAC) consolekeys[K_COMMAND] = true; #endif consolekeys[K_MWHEELUP] = true; consolekeys[K_MWHEELDOWN] = true; // // initialize menubound[] // menubound[K_ESCAPE] = true; for (i = 0; i < 12; i++) menubound[K_F1+i] = true; // // register our functions // Cmd_AddCommand ("bindlist",Key_Bindlist_f); //johnfitz Cmd_AddCommand ("bind",Key_Bind_f); Cmd_AddCommand ("unbind",Key_Unbind_f); Cmd_AddCommand ("unbindall",Key_Unbindall_f); } static struct { qboolean active; int lastkey; int lastchar; } key_inputgrab = { false, -1, -1 }; /* =================== Key_BeginInputGrab =================== */ void Key_BeginInputGrab (void) { Key_ClearStates (); key_inputgrab.active = true; key_inputgrab.lastkey = -1; key_inputgrab.lastchar = -1; IN_UpdateInputMode (); } /* =================== Key_EndInputGrab =================== */ void Key_EndInputGrab (void) { Key_ClearStates (); key_inputgrab.active = false; IN_UpdateInputMode (); } /* =================== Key_GetGrabbedInput =================== */ void Key_GetGrabbedInput (int *lastkey, int *lastchar) { if (lastkey) *lastkey = key_inputgrab.lastkey; if (lastchar) *lastchar = key_inputgrab.lastchar; } /* =================== Key_Event Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! =================== */ void Key_Event (int key, qboolean down) { char *kb; char cmd[1024]; if (key < 0 || key >= MAX_KEYS) return; // handle fullscreen toggle if (down && (key == K_ENTER || key == K_KP_ENTER) && keydown[K_ALT]) { VID_Toggle(); return; } // handle autorepeats and stray key up events if (down) { if (keydown[key]) { if (key_dest == key_game && !con_forcedup) return; // ignore autorepeats in game mode } else if (key >= 200 && !keybindings[key]) Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString(key)); } else if (!keydown[key]) return; // ignore stray key up events keydown[key] = down; if (key_inputgrab.active) { if (down) key_inputgrab.lastkey = key; return; } // handle escape specialy, so the user can never unbind it if (key == K_ESCAPE) { if (!down) return; if (keydown[K_SHIFT]) { Con_ToggleConsole_f(); return; } switch (key_dest) { case key_message: Key_Message (key); break; case key_menu: M_Keydown (key); break; case key_game: case key_console: M_ToggleMenu_f (); break; default: Sys_Error ("Bad key_dest"); } return; } // key up events only generate commands if the game key binding is // a button command (leading + sign). These will occur even in console mode, // to keep the character from continuing an action started before a console // switch. Button commands include the kenum as a parameter, so multiple // downs can be matched with ups if (!down) { kb = keybindings[key]; if (kb && kb[0] == '+') { sprintf (cmd, "-%s %i\n", kb+1, key); Cbuf_AddText (cmd); } return; } // during demo playback, most keys bring up the main menu if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game && key != K_TAB) { M_ToggleMenu_f (); return; } // if not a consolekey, send to the interpreter no matter what mode is if ((key_dest == key_menu && menubound[key]) || (key_dest == key_console && !consolekeys[key]) || (key_dest == key_game && (!con_forcedup || !consolekeys[key]))) { kb = keybindings[key]; if (kb) { if (kb[0] == '+') { // button commands add keynum as a parm sprintf (cmd, "%s %i\n", kb, key); Cbuf_AddText (cmd); } else { Cbuf_AddText (kb); Cbuf_AddText ("\n"); } } return; } if (!down) return; // other systems only care about key down events switch (key_dest) { case key_message: Key_Message (key); break; case key_menu: M_Keydown (key); break; case key_game: case key_console: Key_Console (key); break; default: Sys_Error ("Bad key_dest"); } } /* =================== Char_Event Called by the backend when the user has input a character. =================== */ void Char_Event (int key) { if (key < 32 || key > 126) return; #if defined(PLATFORM_OSX) || defined(PLATFORM_MAC) if (keydown[K_COMMAND]) return; #endif if (keydown[K_CTRL]) return; if (key_inputgrab.active) { key_inputgrab.lastchar = key; return; } switch (key_dest) { case key_message: Char_Message (key); break; case key_menu: M_Charinput (key); break; case key_game: if (!con_forcedup) break; /* fallthrough */ case key_console: Char_Console (key); break; default: break; } } /* =================== Key_TextEntry =================== */ qboolean Key_TextEntry (void) { if (key_inputgrab.active) return true; switch (key_dest) { case key_message: return true; case key_menu: return M_TextEntry(); case key_game: if (!con_forcedup) return false; /* fallthrough */ case key_console: return true; default: return false; } } /* =================== Key_ClearStates =================== */ void Key_ClearStates (void) { int i; for (i = 0; i < MAX_KEYS; i++) { if (keydown[i]) Key_Event (i, false); } } /* =================== Key_UpdateForDest =================== */ void Key_UpdateForDest (void) { static qboolean forced = false; if (cls.state == ca_dedicated) return; switch (key_dest) { case key_console: if (forced && cls.state == ca_connected) { forced = false; IN_Activate(); key_dest = key_game; } break; case key_game: if (cls.state != ca_connected) { forced = true; IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_console; break; } /* fallthrough */ default: forced = false; break; } } ������quakespasm-0.91.0/Quake/input.h���������������������������������������������������������������������0000644�0000000�0000000�00000003150�12410342612�015021� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_INPUT_H #define _QUAKE_INPUT_H // input.h -- external (non-keyboard) input devices void IN_Init (void); void IN_Shutdown (void); void IN_Commands (void); // oportunity for devices to stick commands on the script buffer // mouse moved by dx and dy pixels void IN_MouseMove(int dx, int dy); void IN_SendKeyEvents (void); // used as a callback for Sys_SendKeyEvents() by some drivers void IN_UpdateInputMode (void); // do stuff if input mode (text/non-text) changes matter to the keyboard driver void IN_Move (usercmd_t *cmd); // add additional movement on top of the keyboard move cmd void IN_ClearStates (void); // restores all button and position states to defaults // called when the app becomes active void IN_Activate (); // called when the app becomes inactive void IN_Deactivate (qboolean free_cursor); #endif /* _QUAKE_INPUT_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/mathlib.h�������������������������������������������������������������������0000644�0000000�0000000�00000007300�12407762022�015312� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __MATHLIB_H #define __MATHLIB_H // mathlib.h #include <math.h> #ifndef M_PI #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h #endif #define M_PI_DIV_180 (M_PI / 180.0) //johnfitz struct mplane_s; extern vec3_t vec3_origin; #define nanmask (255 << 23) /* 7F800000 */ #if 0 /* macro is violating strict aliasing rules */ #define IS_NAN(x) (((*(int *) (char *) &x) & nanmask) == nanmask) #else static inline int IS_NAN (float x) { union { float f; int i; } num; num.f = x; return ((num.i & nanmask) == nanmask); } #endif #define Q_rint(x) ((x) > 0 ? (int)((x) + 0.5) : (int)((x) - 0.5)) //johnfitz -- from joequake #define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) #define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} #define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} #define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} //johnfitz -- courtesy of lordhavoc // QuakeSpasm: To avoid strict aliasing violations, use a float/int union instead of type punning. #define VectorNormalizeFast(_v)\ {\ union { float f; int i; } _y, _number;\ _number.f = DotProduct(_v, _v);\ if (_number.f != 0.0)\ {\ _y.i = 0x5f3759df - (_number.i >> 1);\ _y.f = _y.f * (1.5f - (_number.f * 0.5f * _y.f * _y.f));\ VectorScale(_v, _y.f, _v);\ }\ } void TurnVector (vec3_t out, const vec3_t forward, const vec3_t side, float angle); //johnfitz void VectorAngles (const vec3_t forward, vec3_t angles); //johnfitz void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); vec_t _DotProduct (vec3_t v1, vec3_t v2); void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); void _VectorCopy (vec3_t in, vec3_t out); int VectorCompare (vec3_t v1, vec3_t v2); vec_t VectorLength (vec3_t v); void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); float VectorNormalize (vec3_t v); // returns vector length void VectorInverse (vec3_t v); void VectorScale (vec3_t in, vec_t scale, vec3_t out); int Q_log2(int val); void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); void FloorDivMod (double numer, double denom, int *quotient, int *rem); fixed16_t Invert24To16(fixed16_t val); int GreatestCommonDivisor (int i1, int i2); void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); float anglemod(float a); #define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ (((p)->type < 3)? \ ( \ ((p)->dist <= (emins)[(p)->type])? \ 1 \ : \ ( \ ((p)->dist >= (emaxs)[(p)->type])?\ 2 \ : \ 3 \ ) \ ) \ : \ BoxOnPlaneSide( (emins), (emaxs), (p))) #endif /* __MATHLIB_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_udp.h�������������������������������������������������������������������0000644�0000000�0000000�00000003522�12407762022�015332� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __net_udp_h #define __net_udp_h sys_socket_t UDP_Init (void); void UDP_Shutdown (void); void UDP_Listen (qboolean state); sys_socket_t UDP_OpenSocket (int port); int UDP_CloseSocket (sys_socket_t socketid); int UDP_Connect (sys_socket_t socketid, struct qsockaddr *addr); sys_socket_t UDP_CheckNewConnections (void); int UDP_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr); int UDP_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr); int UDP_Broadcast (sys_socket_t socketid, byte *buf, int len); const char *UDP_AddrToString (struct qsockaddr *addr); int UDP_StringToAddr (const char *string, struct qsockaddr *addr); int UDP_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr); int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name); int UDP_GetAddrFromName (const char *name, struct qsockaddr *addr); int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); int UDP_GetSocketPort (struct qsockaddr *addr); int UDP_SetSocketPort (struct qsockaddr *addr, int port); #endif /* __net_udp_h */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/world.h���������������������������������������������������������������������0000644�0000000�0000000�00000005442�12407762022�015026� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_WORLD_H #define _QUAKE_WORLD_H typedef struct { vec3_t normal; float dist; } plane_t; typedef struct { qboolean allsolid; // if true, plane is not valid qboolean startsolid; // if true, the initial point was in a solid area qboolean inopen, inwater; float fraction; // time completed, 1.0 = didn't hit anything vec3_t endpos; // final position plane_t plane; // surface normal at impact edict_t *ent; // entity the surface is on } trace_t; #define MOVE_NORMAL 0 #define MOVE_NOMONSTERS 1 #define MOVE_MISSILE 2 void SV_ClearWorld (void); // called after the world model has been loaded, before linking any entities void SV_UnlinkEdict (edict_t *ent); // call before removing an entity, and before trying to move one, // so it doesn't clip against itself // flags ent->v.modified void SV_LinkEdict (edict_t *ent, qboolean touch_triggers); // Needs to be called any time an entity changes origin, mins, maxs, or solid // flags ent->v.modified // sets ent->v.absmin and ent->v.absmax // if touchtriggers, calls prog functions for the intersected triggers int SV_PointContents (vec3_t p); int SV_TruePointContents (vec3_t p); // returns the CONTENTS_* value from the world at the given point. // does not check any entities at all // the non-true version remaps the water current contents to content_water edict_t *SV_TestEntityPosition (edict_t *ent); trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict); // mins and maxs are reletive // if the entire move stays in a solid volume, trace.allsolid will be set // if the starting point is in a solid, it will be allowed to move out // to an open area // nomonsters is used for line of sight or edge testing, where mosnters // shouldn't be considered solid objects // passedict is explicitly excluded from clipping checks (normally NULL) qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace); #endif /* _QUAKE_WORLD_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_mpg123.c����������������������������������������������������������������0000644�0000000�0000000�00000012537�12471320271�015547� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * MP3 decoding support using libmpg123, loosely based on an SDL_mixer * See: http://bubu.lv/changeset/4/public/libs/SDL/generated/SDL_mixer * * Copyright (C) 2011-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #include "quakedef.h" #if defined(USE_CODEC_MP3) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_mp3.h" #include <errno.h> #include <mpg123.h> #if !defined(MPG123_API_VERSION) || (MPG123_API_VERSION < 24) #error minimum required libmpg123 version is 1.12.0 (api version 24) #endif /* MPG123_API_VERSION */ /* Private data */ typedef struct _mp3_priv_t { int handle_newed, handle_opened; mpg123_handle* handle; } mp3_priv_t; /* CALLBACK FUNCTIONS: */ /* CAREFUL: libmpg123 expects POSIX read() and lseek() behavior, * however our FS_fread() and FS_fseek() return fread() and fseek() * compatible values. */ static ssize_t mp3_read (void *f, void *buf, size_t size) { ssize_t ret = (ssize_t) FS_fread(buf, 1, size, (fshandle_t *)f); if (ret == 0 && errno != 0) ret = -1; return ret; } static off_t mp3_seek (void *f, off_t offset, int whence) { if (f == NULL) return (-1); if (FS_fseek((fshandle_t *)f, (long) offset, whence) < 0) return (off_t)-1; return (off_t) FS_ftell((fshandle_t *)f); } static qboolean S_MP3_CodecInitialize (void) { if (!mp3_codec.initialized) { if (mpg123_init() != MPG123_OK) { Con_Printf ("Could not initialize mpg123\n"); return false; } mp3_codec.initialized = true; return true; } return true; } static void S_MP3_CodecShutdown (void) { if (mp3_codec.initialized) { mp3_codec.initialized = false; mpg123_exit(); } } static qboolean S_MP3_CodecOpenStream (snd_stream_t *stream) { long rate = 0; int encoding = 0, channels = 0; mp3_priv_t *priv = NULL; stream->priv = Z_Malloc(sizeof(mp3_priv_t)); priv = (mp3_priv_t *) stream->priv; priv->handle = mpg123_new(NULL, NULL); if (priv->handle == NULL) { Con_Printf("Unable to allocate mpg123 handle\n"); goto _fail; } priv->handle_newed = 1; if (mpg123_replace_reader_handle(priv->handle, mp3_read, mp3_seek, NULL) != MPG123_OK || mpg123_open_handle(priv->handle, &stream->fh) != MPG123_OK) { Con_Printf("Unable to open mpg123 handle\n"); goto _fail; } priv->handle_opened = 1; if (mpg123_getformat(priv->handle, &rate, &channels, &encoding) != MPG123_OK) { Con_Printf("Unable to retrieve mpg123 format for %s\n", stream->name); goto _fail; } switch (channels) { case MPG123_MONO: stream->info.channels = 1; break; case MPG123_STEREO: stream->info.channels = 2; break; default: Con_Printf("Unsupported number of channels %d in %s\n", channels, stream->name); goto _fail; } stream->info.rate = rate; switch (encoding) { case MPG123_ENC_UNSIGNED_8: stream->info.bits = 8; stream->info.width = 1; break; case MPG123_ENC_SIGNED_8: /* unsupported: force mpg123 to convert */ stream->info.bits = 8; stream->info.width = 1; encoding = MPG123_ENC_UNSIGNED_8; break; case MPG123_ENC_SIGNED_16: stream->info.bits = 16; stream->info.width = 2; break; case MPG123_ENC_UNSIGNED_16: default: /* unsupported: force mpg123 to convert */ stream->info.bits = 16; stream->info.width = 2; encoding = MPG123_ENC_SIGNED_16; break; } if (mpg123_format_support(priv->handle, rate, encoding) == 0) { Con_Printf("Unsupported format for %s\n", stream->name); goto _fail; } mpg123_format_none(priv->handle); mpg123_format(priv->handle, rate, channels, encoding); return true; _fail: if (priv) { if (priv->handle_opened) mpg123_close(priv->handle); if (priv->handle_newed) mpg123_delete(priv->handle); Z_Free(stream->priv); } return false; } static int S_MP3_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) { mp3_priv_t *priv = (mp3_priv_t *) stream->priv; size_t bytes_read = 0; int res = mpg123_read (priv->handle, (unsigned char *)buffer, (size_t)bytes, &bytes_read); switch (res) { case MPG123_DONE: Con_DPrintf("mp3 EOF\n"); case MPG123_OK: return (int)bytes_read; } return -1; /* error */ } static void S_MP3_CodecCloseStream (snd_stream_t *stream) { mp3_priv_t *priv = (mp3_priv_t *) stream->priv; mpg123_close(priv->handle); mpg123_delete(priv->handle); Z_Free(stream->priv); S_CodecUtilClose(&stream); } static int S_MP3_CodecRewindStream (snd_stream_t *stream) { mp3_priv_t *priv = (mp3_priv_t *) stream->priv; off_t res = mpg123_seek(priv->handle, 0, SEEK_SET); if (res >= 0) return (0); return res; } snd_codec_t mp3_codec = { CODECTYPE_MP3, false, "mp3", S_MP3_CodecInitialize, S_MP3_CodecShutdown, S_MP3_CodecOpenStream, S_MP3_CodecReadStream, S_MP3_CodecRewindStream, S_MP3_CodecCloseStream, NULL }; #endif /* USE_CODEC_MP3 */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_dgrm.c������������������������������������������������������������������0000644�0000000�0000000�00000102133�12407762022�015464� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // This is enables a simple IP banning mechanism #define BAN_TEST #include "q_stdinc.h" #include "arch_def.h" #include "net_sys.h" #include "quakedef.h" #include "net_defs.h" #include "net_dgrm.h" // these two macros are to make the code more readable #define sfunc net_landrivers[sock->landriver] #define dfunc net_landrivers[net_landriverlevel] static int net_landriverlevel; /* statistic counters */ static int packetsSent = 0; static int packetsReSent = 0; static int packetsReceived = 0; static int receivedDuplicateCount = 0; static int shortPacketCount = 0; static int droppedDatagrams; static struct { unsigned int length; unsigned int sequence; byte data[MAX_DATAGRAM]; } packetBuffer; static int myDriverLevel; extern qboolean m_return_onerror; extern char m_return_reason[32]; static char *StrAddr (struct qsockaddr *addr) { static char buf[34]; byte *p = (byte *)addr; int n; for (n = 0; n < 16; n++) sprintf (buf + n * 2, "%02x", *p++); return buf; } #ifdef BAN_TEST static struct in_addr banAddr; static struct in_addr banMask; static void NET_Ban_f (void) { char addrStr [32]; char maskStr [32]; void (*print_fn)(const char *fmt, ...) __fp_attribute__((__format__(__printf__,1,2))); if (cmd_source == src_command) { if (!sv.active) { Cmd_ForwardToServer (); return; } print_fn = Con_Printf; } else { if (pr_global_struct->deathmatch) return; print_fn = SV_ClientPrintf; } switch (Cmd_Argc ()) { case 1: if (banAddr.s_addr != INADDR_ANY) { Q_strcpy(addrStr, inet_ntoa(banAddr)); Q_strcpy(maskStr, inet_ntoa(banMask)); print_fn("Banning %s [%s]\n", addrStr, maskStr); } else print_fn("Banning not active\n"); break; case 2: if (q_strcasecmp(Cmd_Argv(1), "off") == 0) banAddr.s_addr = INADDR_ANY; else banAddr.s_addr = inet_addr(Cmd_Argv(1)); banMask.s_addr = INADDR_NONE; break; case 3: banAddr.s_addr = inet_addr(Cmd_Argv(1)); banMask.s_addr = inet_addr(Cmd_Argv(2)); break; default: print_fn("BAN ip_address [mask]\n"); break; } } #endif // BAN_TEST int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data) { unsigned int packetLen; unsigned int dataLen; unsigned int eom; #ifdef DEBUG if (data->cursize == 0) Sys_Error("Datagram_SendMessage: zero length message\n"); if (data->cursize > NET_MAXMESSAGE) Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize); if (sock->canSend == false) Sys_Error("SendMessage: called with canSend == false\n"); #endif Q_memcpy(sock->sendMessage, data->data, data->cursize); sock->sendMessageLength = data->cursize; if (data->cursize <= MAX_DATAGRAM) { dataLen = data->cursize; eom = NETFLAG_EOM; } else { dataLen = MAX_DATAGRAM; eom = 0; } packetLen = NET_HEADERSIZE + dataLen; packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); packetBuffer.sequence = BigLong(sock->sendSequence++); Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); sock->canSend = false; if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) return -1; sock->lastSendTime = net_time; packetsSent++; return 1; } static int SendMessageNext (qsocket_t *sock) { unsigned int packetLen; unsigned int dataLen; unsigned int eom; if (sock->sendMessageLength <= MAX_DATAGRAM) { dataLen = sock->sendMessageLength; eom = NETFLAG_EOM; } else { dataLen = MAX_DATAGRAM; eom = 0; } packetLen = NET_HEADERSIZE + dataLen; packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); packetBuffer.sequence = BigLong(sock->sendSequence++); Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); sock->sendNext = false; if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) return -1; sock->lastSendTime = net_time; packetsSent++; return 1; } static int ReSendMessage (qsocket_t *sock) { unsigned int packetLen; unsigned int dataLen; unsigned int eom; if (sock->sendMessageLength <= MAX_DATAGRAM) { dataLen = sock->sendMessageLength; eom = NETFLAG_EOM; } else { dataLen = MAX_DATAGRAM; eom = 0; } packetLen = NET_HEADERSIZE + dataLen; packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); packetBuffer.sequence = BigLong(sock->sendSequence - 1); Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); sock->sendNext = false; if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) return -1; sock->lastSendTime = net_time; packetsReSent++; return 1; } qboolean Datagram_CanSendMessage (qsocket_t *sock) { if (sock->sendNext) SendMessageNext (sock); return sock->canSend; } qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock) { return true; } int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) { int packetLen; #ifdef DEBUG if (data->cursize == 0) Sys_Error("Datagram_SendUnreliableMessage: zero length message\n"); if (data->cursize > MAX_DATAGRAM) Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize); #endif packetLen = NET_HEADERSIZE + data->cursize; packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE); packetBuffer.sequence = BigLong(sock->unreliableSendSequence++); Q_memcpy (packetBuffer.data, data->data, data->cursize); if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) return -1; packetsSent++; return 1; } int Datagram_GetMessage (qsocket_t *sock) { unsigned int length; unsigned int flags; int ret = 0; struct qsockaddr readaddr; unsigned int sequence; unsigned int count; if (!sock->canSend) if ((net_time - sock->lastSendTime) > 1.0) ReSendMessage (sock); while (1) { length = (unsigned int) sfunc.Read(sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr); // if ((rand() & 255) > 220) // continue; if (length == 0) break; if (length == (unsigned int)-1) { Con_Printf("Read error\n"); return -1; } if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0) { Con_Printf("Forged packet received\n"); Con_Printf("Expected: %s\n", StrAddr (&sock->addr)); Con_Printf("Received: %s\n", StrAddr (&readaddr)); continue; } if (length < NET_HEADERSIZE) { shortPacketCount++; continue; } length = BigLong(packetBuffer.length); flags = length & (~NETFLAG_LENGTH_MASK); length &= NETFLAG_LENGTH_MASK; if (flags & NETFLAG_CTL) continue; sequence = BigLong(packetBuffer.sequence); packetsReceived++; if (flags & NETFLAG_UNRELIABLE) { if (sequence < sock->unreliableReceiveSequence) { Con_DPrintf("Got a stale datagram\n"); ret = 0; break; } if (sequence != sock->unreliableReceiveSequence) { count = sequence - sock->unreliableReceiveSequence; droppedDatagrams += count; Con_DPrintf("Dropped %u datagram(s)\n", count); } sock->unreliableReceiveSequence = sequence + 1; length -= NET_HEADERSIZE; SZ_Clear (&net_message); SZ_Write (&net_message, packetBuffer.data, length); ret = 2; break; } if (flags & NETFLAG_ACK) { if (sequence != (sock->sendSequence - 1)) { Con_DPrintf("Stale ACK received\n"); continue; } if (sequence == sock->ackSequence) { sock->ackSequence++; if (sock->ackSequence != sock->sendSequence) Con_DPrintf("ack sequencing error\n"); } else { Con_DPrintf("Duplicate ACK received\n"); continue; } sock->sendMessageLength -= MAX_DATAGRAM; if (sock->sendMessageLength > 0) { memmove (sock->sendMessage, sock->sendMessage + MAX_DATAGRAM, sock->sendMessageLength); sock->sendNext = true; } else { sock->sendMessageLength = 0; sock->canSend = true; } continue; } if (flags & NETFLAG_DATA) { packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK); packetBuffer.sequence = BigLong(sequence); sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr); if (sequence != sock->receiveSequence) { receivedDuplicateCount++; continue; } sock->receiveSequence++; length -= NET_HEADERSIZE; if (flags & NETFLAG_EOM) { SZ_Clear(&net_message); SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength); SZ_Write(&net_message, packetBuffer.data, length); sock->receiveMessageLength = 0; ret = 1; break; } Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length); sock->receiveMessageLength += length; continue; } } if (sock->sendNext) SendMessageNext (sock); return ret; } static void PrintStats(qsocket_t *s) { Con_Printf("canSend = %4u \n", s->canSend); Con_Printf("sendSeq = %4u ", s->sendSequence); Con_Printf("recvSeq = %4u \n", s->receiveSequence); Con_Printf("\n"); } static void NET_Stats_f (void) { qsocket_t *s; if (Cmd_Argc () == 1) { Con_Printf("unreliable messages sent = %i\n", unreliableMessagesSent); Con_Printf("unreliable messages recv = %i\n", unreliableMessagesReceived); Con_Printf("reliable messages sent = %i\n", messagesSent); Con_Printf("reliable messages received = %i\n", messagesReceived); Con_Printf("packetsSent = %i\n", packetsSent); Con_Printf("packetsReSent = %i\n", packetsReSent); Con_Printf("packetsReceived = %i\n", packetsReceived); Con_Printf("receivedDuplicateCount = %i\n", receivedDuplicateCount); Con_Printf("shortPacketCount = %i\n", shortPacketCount); Con_Printf("droppedDatagrams = %i\n", droppedDatagrams); } else if (Q_strcmp(Cmd_Argv(1), "*") == 0) { for (s = net_activeSockets; s; s = s->next) PrintStats(s); for (s = net_freeSockets; s; s = s->next) PrintStats(s); } else { for (s = net_activeSockets; s; s = s->next) { if (q_strcasecmp(Cmd_Argv(1), s->address) == 0) break; } if (s == NULL) { for (s = net_freeSockets; s; s = s->next) { if (q_strcasecmp(Cmd_Argv(1), s->address) == 0) break; } } if (s == NULL) return; PrintStats(s); } } // recognize ip:port (based on ProQuake) static const char *Strip_Port (const char *host) { static char noport[MAX_QPATH]; /* array size as in Host_Connect_f() */ char *p; int port; if (!host || !*host) return host; q_strlcpy (noport, host, sizeof(noport)); if ((p = Q_strrchr(noport, ':')) == NULL) return host; *p++ = '\0'; port = Q_atoi (p); if (port > 0 && port < 65536 && port != net_hostport) { net_hostport = port; Con_Printf("Port set to %d\n", net_hostport); } return noport; } static qboolean testInProgress = false; static int testPollCount; static int testDriver; static sys_socket_t testSocket; static void Test_Poll (void *); static PollProcedure testPollProcedure = {NULL, 0.0, Test_Poll}; static void Test_Poll (void *unused) { struct qsockaddr clientaddr; int control; int len; char name[32]; char address[64]; int colors; int frags; int connectTime; net_landriverlevel = testDriver; while (1) { len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr); if (len < (int) sizeof(int)) break; net_message.cursize = len; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) break; if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL) break; if ((control & NETFLAG_LENGTH_MASK) != len) break; if (MSG_ReadByte() != CCREP_PLAYER_INFO) Sys_Error("Unexpected repsonse to Player Info request\n"); MSG_ReadByte(); /* playerNumber */ Q_strcpy(name, MSG_ReadString()); colors = MSG_ReadLong(); frags = MSG_ReadLong(); connectTime = MSG_ReadLong(); Q_strcpy(address, MSG_ReadString()); Con_Printf("%s\n frags:%3i colors:%d %d time:%d\n %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address); } testPollCount--; if (testPollCount) { SchedulePollProcedure(&testPollProcedure, 0.1); } else { dfunc.Close_Socket(testSocket); testInProgress = false; } } static void Test_f (void) { const char *host; int n; int maxusers = MAX_SCOREBOARD; struct qsockaddr sendaddr; if (testInProgress) return; host = Strip_Port (Cmd_Argv(1)); if (host && hostCacheCount) { for (n = 0; n < hostCacheCount; n++) { if (q_strcasecmp (host, hostcache[n].name) == 0) { if (hostcache[n].driver != myDriverLevel) continue; net_landriverlevel = hostcache[n].ldriver; maxusers = hostcache[n].maxusers; Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); break; } } if (n < hostCacheCount) goto JustDoIt; } for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) { if (!net_landrivers[net_landriverlevel].initialized) continue; // see if we can resolve the host name if (dfunc.GetAddrFromName(host, &sendaddr) != -1) break; } if (net_landriverlevel == net_numlandrivers) { Con_Printf("Could not resolve %s\n", host); return; } JustDoIt: testSocket = dfunc.Open_Socket(0); if (testSocket == INVALID_SOCKET) return; testInProgress = true; testPollCount = 20; testDriver = net_landriverlevel; for (n = 0; n < maxusers; n++) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO); MSG_WriteByte(&net_message, n); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr); } SZ_Clear(&net_message); SchedulePollProcedure(&testPollProcedure, 0.1); } static qboolean test2InProgress = false; static int test2Driver; static sys_socket_t test2Socket; static void Test2_Poll (void *); static PollProcedure test2PollProcedure = {NULL, 0.0, Test2_Poll}; static void Test2_Poll (void *unused) { struct qsockaddr clientaddr; int control; int len; char name[256]; char value[256]; net_landriverlevel = test2Driver; name[0] = 0; len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr); if (len < (int) sizeof(int)) goto Reschedule; net_message.cursize = len; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) goto Error; if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL) goto Error; if ((control & NETFLAG_LENGTH_MASK) != len) goto Error; if (MSG_ReadByte() != CCREP_RULE_INFO) goto Error; Q_strcpy(name, MSG_ReadString()); if (name[0] == 0) goto Done; Q_strcpy(value, MSG_ReadString()); Con_Printf("%-16.16s %-16.16s\n", name, value); SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_RULE_INFO); MSG_WriteString(&net_message, name); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); Reschedule: SchedulePollProcedure(&test2PollProcedure, 0.05); return; Error: Con_Printf("Unexpected repsonse to Rule Info request\n"); Done: dfunc.Close_Socket(test2Socket); test2InProgress = false; return; } static void Test2_f (void) { const char *host; int n; struct qsockaddr sendaddr; if (test2InProgress) return; host = Strip_Port (Cmd_Argv(1)); if (host && hostCacheCount) { for (n = 0; n < hostCacheCount; n++) { if (q_strcasecmp (host, hostcache[n].name) == 0) { if (hostcache[n].driver != myDriverLevel) continue; net_landriverlevel = hostcache[n].ldriver; Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); break; } } if (n < hostCacheCount) goto JustDoIt; } for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) { if (!net_landrivers[net_landriverlevel].initialized) continue; // see if we can resolve the host name if (dfunc.GetAddrFromName(host, &sendaddr) != -1) break; } if (net_landriverlevel == net_numlandrivers) { Con_Printf("Could not resolve %s\n", host); return; } JustDoIt: test2Socket = dfunc.Open_Socket(0); if (test2Socket == INVALID_SOCKET) return; test2InProgress = true; test2Driver = net_landriverlevel; SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_RULE_INFO); MSG_WriteString(&net_message, ""); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr); SZ_Clear(&net_message); SchedulePollProcedure(&test2PollProcedure, 0.05); } int Datagram_Init (void) { int i, num_inited; sys_socket_t csock; #ifdef BAN_TEST banAddr.s_addr = INADDR_ANY; banMask.s_addr = INADDR_NONE; #endif myDriverLevel = net_driverlevel; Cmd_AddCommand ("net_stats", NET_Stats_f); if (safemode || COM_CheckParm("-nolan")) return -1; num_inited = 0; for (i = 0; i < net_numlandrivers; i++) { csock = net_landrivers[i].Init (); if (csock == INVALID_SOCKET) continue; net_landrivers[i].initialized = true; net_landrivers[i].controlSock = csock; num_inited++; } if (num_inited == 0) return -1; #ifdef BAN_TEST Cmd_AddCommand ("ban", NET_Ban_f); #endif Cmd_AddCommand ("test", Test_f); Cmd_AddCommand ("test2", Test2_f); return 0; } void Datagram_Shutdown (void) { int i; // // shutdown the lan drivers // for (i = 0; i < net_numlandrivers; i++) { if (net_landrivers[i].initialized) { net_landrivers[i].Shutdown (); net_landrivers[i].initialized = false; } } } void Datagram_Close (qsocket_t *sock) { sfunc.Close_Socket(sock->socket); } void Datagram_Listen (qboolean state) { int i; for (i = 0; i < net_numlandrivers; i++) { if (net_landrivers[i].initialized) net_landrivers[i].Listen (state); } } static qsocket_t *_Datagram_CheckNewConnections (void) { struct qsockaddr clientaddr; struct qsockaddr newaddr; sys_socket_t newsock; sys_socket_t acceptsock; qsocket_t *sock; qsocket_t *s; int len; int command; int control; int ret; acceptsock = dfunc.CheckNewConnections(); if (acceptsock == INVALID_SOCKET) return NULL; SZ_Clear(&net_message); len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr); if (len < (int) sizeof(int)) return NULL; net_message.cursize = len; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) return NULL; if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL) return NULL; if ((control & NETFLAG_LENGTH_MASK) != len) return NULL; command = MSG_ReadByte(); if (command == CCREQ_SERVER_INFO) { if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) return NULL; SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_SERVER_INFO); dfunc.GetSocketAddr(acceptsock, &newaddr); MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); MSG_WriteString(&net_message, hostname.string); MSG_WriteString(&net_message, sv.name); MSG_WriteByte(&net_message, net_activeconnections); MSG_WriteByte(&net_message, svs.maxclients); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command == CCREQ_PLAYER_INFO) { int playerNumber; int activeNumber; int clientNumber; client_t *client; playerNumber = MSG_ReadByte(); activeNumber = -1; for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) { if (client->active) { activeNumber++; if (activeNumber == playerNumber) break; } } if (clientNumber == svs.maxclients) return NULL; SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_PLAYER_INFO); MSG_WriteByte(&net_message, playerNumber); MSG_WriteString(&net_message, client->name); MSG_WriteLong(&net_message, client->colors); MSG_WriteLong(&net_message, (int)client->edict->v.frags); MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime)); MSG_WriteString(&net_message, client->netconnection->address); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command == CCREQ_RULE_INFO) { const char *prevCvarName; cvar_t *var; // find the search start location prevCvarName = MSG_ReadString(); var = Cvar_FindVarAfter (prevCvarName, CVAR_SERVERINFO); // send the response SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_RULE_INFO); if (var) { MSG_WriteString(&net_message, var->name); MSG_WriteString(&net_message, var->string); } *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command != CCREQ_CONNECT) return NULL; if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) return NULL; if (MSG_ReadByte() != NET_PROTOCOL_VERSION) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "Incompatible version.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } #ifdef BAN_TEST // check for a ban if (clientaddr.qsa_family == AF_INET) { in_addr_t testAddr; testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr; if ((testAddr & banMask.s_addr) == banAddr.s_addr) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "You have been banned.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } } #endif // see if this guy is already connected for (s = net_activeSockets; s; s = s->next) { if (s->driver != net_driverlevel) continue; ret = dfunc.AddrCompare(&clientaddr, &s->addr); if (ret >= 0) { // is this a duplicate connection reqeust? if (ret == 0 && net_time - s->connecttime < 2.0) { // yes, so send a duplicate reply SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_ACCEPT); dfunc.GetSocketAddr(s->socket, &newaddr); MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } // it's somebody coming back in from a crash/disconnect // so close the old qsocket and let their retry get them back in NET_Close(s); return NULL; } } // allocate a QSocket sock = NET_NewQSocket (); if (sock == NULL) { // no room; try to let him know SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "Server is full.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } // allocate a network socket newsock = dfunc.Open_Socket(0); if (newsock == INVALID_SOCKET) { NET_FreeQSocket(sock); return NULL; } // connect to the client if (dfunc.Connect (newsock, &clientaddr) == -1) { dfunc.Close_Socket(newsock); NET_FreeQSocket(sock); return NULL; } // everything is allocated, just fill in the details sock->socket = newsock; sock->landriver = net_landriverlevel; sock->addr = clientaddr; Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr)); // send him back the info about the server connection he has been allocated SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_ACCEPT); dfunc.GetSocketAddr(newsock, &newaddr); MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); // MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return sock; } qsocket_t *Datagram_CheckNewConnections (void) { qsocket_t *ret = NULL; for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) { if (net_landrivers[net_landriverlevel].initialized) { if ((ret = _Datagram_CheckNewConnections ()) != NULL) break; } } return ret; } static void _Datagram_SearchForHosts (qboolean xmit) { int ret; int n; int i; struct qsockaddr readaddr; struct qsockaddr myaddr; int control; dfunc.GetSocketAddr (dfunc.controlSock, &myaddr); if (xmit) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_SERVER_INFO); MSG_WriteString(&net_message, "QUAKE"); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize); SZ_Clear(&net_message); } while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0) { if (ret < (int) sizeof(int)) continue; net_message.cursize = ret; // don't answer our own query if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0) continue; // is the cache full? if (hostCacheCount == HOSTCACHESIZE) continue; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) continue; if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL) continue; if ((control & NETFLAG_LENGTH_MASK) != ret) continue; if (MSG_ReadByte() != CCREP_SERVER_INFO) continue; dfunc.GetAddrFromName(MSG_ReadString(), &readaddr); // search the cache for this server for (n = 0; n < hostCacheCount; n++) { if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0) break; } // is it already there? if (n < hostCacheCount) continue; // add it hostCacheCount++; Q_strcpy(hostcache[n].name, MSG_ReadString()); Q_strcpy(hostcache[n].map, MSG_ReadString()); hostcache[n].users = MSG_ReadByte(); hostcache[n].maxusers = MSG_ReadByte(); if (MSG_ReadByte() != NET_PROTOCOL_VERSION) { Q_strcpy(hostcache[n].cname, hostcache[n].name); hostcache[n].cname[14] = 0; Q_strcpy(hostcache[n].name, "*"); Q_strcat(hostcache[n].name, hostcache[n].cname); } Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr)); hostcache[n].driver = net_driverlevel; hostcache[n].ldriver = net_landriverlevel; Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr)); // check for a name conflict for (i = 0; i < hostCacheCount; i++) { if (i == n) continue; if (q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0) { i = Q_strlen(hostcache[n].name); if (i < 15 && hostcache[n].name[i-1] > '8') { hostcache[n].name[i] = '0'; hostcache[n].name[i+1] = 0; } else hostcache[n].name[i-1]++; i = -1; } } } } void Datagram_SearchForHosts (qboolean xmit) { for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) { if (hostCacheCount == HOSTCACHESIZE) break; if (net_landrivers[net_landriverlevel].initialized) _Datagram_SearchForHosts (xmit); } } static qsocket_t *_Datagram_Connect (const char *host) { struct qsockaddr sendaddr; struct qsockaddr readaddr; qsocket_t *sock; sys_socket_t newsock; int ret; int reps; double start_time; int control; const char *reason; // see if we can resolve the host name if (dfunc.GetAddrFromName(host, &sendaddr) == -1) { Con_Printf("Could not resolve %s\n", host); return NULL; } newsock = dfunc.Open_Socket (0); if (newsock == INVALID_SOCKET) return NULL; sock = NET_NewQSocket (); if (sock == NULL) goto ErrorReturn2; sock->socket = newsock; sock->landriver = net_landriverlevel; // connect to the host if (dfunc.Connect (newsock, &sendaddr) == -1) goto ErrorReturn; // send the connection request Con_Printf("trying...\n"); SCR_UpdateScreen (); start_time = net_time; for (reps = 0; reps < 3; reps++) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_CONNECT); MSG_WriteString(&net_message, "QUAKE"); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr); SZ_Clear(&net_message); do { ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr); // if we got something, validate it if (ret > 0) { // is it from the right place? if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0) { Con_Printf("wrong reply address\n"); Con_Printf("Expected: %s | %s\n", dfunc.AddrToString (&sendaddr), StrAddr(&sendaddr)); Con_Printf("Received: %s | %s\n", dfunc.AddrToString (&readaddr), StrAddr(&readaddr)); SCR_UpdateScreen (); ret = 0; continue; } if (ret < (int) sizeof(int)) { ret = 0; continue; } net_message.cursize = ret; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { ret = 0; continue; } if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL) { ret = 0; continue; } if ((control & NETFLAG_LENGTH_MASK) != ret) { ret = 0; continue; } } } while (ret == 0 && (SetNetTime() - start_time) < 2.5); if (ret) break; Con_Printf("still trying...\n"); SCR_UpdateScreen (); start_time = SetNetTime(); } if (ret == 0) { reason = "No Response"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } if (ret == -1) { reason = "Network Error"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } ret = MSG_ReadByte(); if (ret == CCREP_REJECT) { reason = MSG_ReadString(); Con_Printf("%s\n", reason); q_strlcpy(m_return_reason, reason, sizeof(m_return_reason)); goto ErrorReturn; } if (ret == CCREP_ACCEPT) { Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr)); dfunc.SetSocketPort (&sock->addr, MSG_ReadLong()); } else { reason = "Bad Response"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } dfunc.GetNameFromAddr (&sendaddr, sock->address); Con_Printf ("Connection accepted\n"); sock->lastMessageTime = SetNetTime(); // switch the connection to the specified address if (dfunc.Connect (newsock, &sock->addr) == -1) { reason = "Connect to Game failed"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } m_return_onerror = false; return sock; ErrorReturn: NET_FreeQSocket(sock); ErrorReturn2: dfunc.Close_Socket(newsock); if (m_return_onerror) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_return_state; m_return_onerror = false; } return NULL; } qsocket_t *Datagram_Connect (const char *host) { qsocket_t *ret = NULL; host = Strip_Port (host); for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) { if (net_landrivers[net_landriverlevel].initialized) { if ((ret = _Datagram_Connect (host)) != NULL) break; } } return ret; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/qs_bmp.h��������������������������������������������������������������������0000644�0000000�0000000�00000043243�12030217765�015162� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0x42, 0x4d, 0xc6, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x02, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x00, 0x05, 0x06, 0x07, 0x00, 0x06, 0x06, 0x07, 0x00, 0x07, 0x06, 0x07, 0x00, 0x06, 0x07, 0x06, 0x00, 0x06, 0x07, 0x07, 0x00, 0x07, 0x07, 0x07, 0x00, 0x07, 0x08, 0x07, 0x00, 0x08, 0x08, 0x08, 0x00, 0x07, 0x08, 0x09, 0x00, 0x08, 0x08, 0x09, 0x00, 0x07, 0x09, 0x08, 0x00, 0x08, 0x09, 0x08, 0x00, 0x09, 0x09, 0x08, 0x00, 0x08, 0x09, 0x09, 0x00, 0x09, 0x09, 0x09, 0x00, 0x08, 0x09, 0x0a, 0x00, 0x09, 0x09, 0x0a, 0x00, 0x09, 0x09, 0x0b, 0x00, 0x09, 0x0a, 0x09, 0x00, 0x08, 0x0a, 0x0a, 0x00, 0x09, 0x0a, 0x0a, 0x00, 0x0a, 0x0a, 0x0a, 0x00, 0x09, 0x0a, 0x0b, 0x00, 0x0a, 0x0a, 0x0b, 0x00, 0x09, 0x0a, 0x0c, 0x00, 0x09, 0x0b, 0x0b, 0x00, 0x0a, 0x0b, 0x0b, 0x00, 0x0a, 0x0b, 0x0c, 0x00, 0x0b, 0x0b, 0x0c, 0x00, 0x0a, 0x0b, 0x0d, 0x00, 0x0b, 0x0c, 0x0c, 0x00, 0x0b, 0x0c, 0x0d, 0x00, 0x0a, 0x0c, 0x0e, 0x00, 0x0b, 0x0c, 0x0e, 0x00, 0x0c, 0x0c, 0x0f, 0x00, 0x0b, 0x0d, 0x0d, 0x00, 0x0b, 0x0d, 0x0e, 0x00, 0x0c, 0x0d, 0x0e, 0x00, 0x0c, 0x0d, 0x0f, 0x00, 0x0d, 0x0d, 0x0f, 0x00, 0x0b, 0x0d, 0x10, 0x00, 0x0c, 0x0d, 0x10, 0x00, 0x0c, 0x0e, 0x0f, 0x00, 0x0d, 0x0e, 0x0f, 0x00, 0x0c, 0x0e, 0x10, 0x00, 0x0d, 0x0e, 0x10, 0x00, 0x0b, 0x0e, 0x11, 0x00, 0x0c, 0x0e, 0x11, 0x00, 0x0d, 0x0e, 0x11, 0x00, 0x0d, 0x0f, 0x10, 0x00, 0x0d, 0x0f, 0x11, 0x00, 0x0e, 0x0f, 0x11, 0x00, 0x0d, 0x0f, 0x12, 0x00, 0x0e, 0x0f, 0x12, 0x00, 0x0d, 0x0f, 0x13, 0x00, 0x0e, 0x10, 0x11, 0x00, 0x0d, 0x10, 0x12, 0x00, 0x0b, 0x10, 0x13, 0x00, 0x0e, 0x10, 0x12, 0x00, 0x0e, 0x10, 0x13, 0x00, 0x0d, 0x10, 0x14, 0x00, 0x0e, 0x10, 0x14, 0x00, 0x0d, 0x11, 0x13, 0x00, 0x0e, 0x11, 0x13, 0x00, 0x0f, 0x11, 0x13, 0x00, 0x0e, 0x11, 0x14, 0x00, 0x0f, 0x11, 0x14, 0x00, 0x0f, 0x11, 0x15, 0x00, 0x0f, 0x12, 0x14, 0x00, 0x0f, 0x12, 0x15, 0x00, 0x10, 0x12, 0x15, 0x00, 0x0f, 0x12, 0x16, 0x00, 0x10, 0x12, 0x16, 0x00, 0x0f, 0x12, 0x17, 0x00, 0x0f, 0x13, 0x16, 0x00, 0x10, 0x13, 0x16, 0x00, 0x10, 0x13, 0x17, 0x00, 0x11, 0x13, 0x17, 0x00, 0x11, 0x13, 0x18, 0x00, 0x10, 0x14, 0x17, 0x00, 0x11, 0x14, 0x17, 0x00, 0x10, 0x14, 0x18, 0x00, 0x12, 0x15, 0x18, 0x00, 0x10, 0x15, 0x19, 0x00, 0x12, 0x15, 0x19, 0x00, 0x10, 0x15, 0x1a, 0x00, 0x11, 0x15, 0x1a, 0x00, 0x12, 0x15, 0x1a, 0x00, 0x12, 0x15, 0x1b, 0x00, 0x11, 0x16, 0x1a, 0x00, 0x12, 0x16, 0x1a, 0x00, 0x13, 0x16, 0x1a, 0x00, 0x12, 0x16, 0x1b, 0x00, 0x13, 0x16, 0x1b, 0x00, 0x12, 0x17, 0x1b, 0x00, 0x13, 0x17, 0x1b, 0x00, 0x13, 0x17, 0x1c, 0x00, 0x14, 0x17, 0x1c, 0x00, 0x14, 0x17, 0x1d, 0x00, 0x13, 0x18, 0x1d, 0x00, 0x14, 0x18, 0x1d, 0x00, 0x15, 0x18, 0x1f, 0x00, 0x14, 0x19, 0x1d, 0x00, 0x15, 0x19, 0x1d, 0x00, 0x15, 0x19, 0x1e, 0x00, 0x15, 0x19, 0x1f, 0x00, 0x16, 0x19, 0x1f, 0x00, 0x15, 0x19, 0x20, 0x00, 0x16, 0x1a, 0x1e, 0x00, 0x14, 0x1a, 0x1f, 0x00, 0x15, 0x1a, 0x1f, 0x00, 0x16, 0x1a, 0x1f, 0x00, 0x15, 0x1a, 0x20, 0x00, 0x16, 0x1a, 0x21, 0x00, 0x15, 0x1b, 0x21, 0x00, 0x17, 0x1b, 0x22, 0x00, 0x17, 0x1b, 0x23, 0x00, 0x16, 0x1c, 0x22, 0x00, 0x17, 0x1d, 0x22, 0x00, 0x17, 0x1d, 0x23, 0x00, 0x18, 0x1d, 0x23, 0x00, 0x19, 0x1d, 0x23, 0x00, 0x17, 0x1d, 0x24, 0x00, 0x18, 0x1e, 0x23, 0x00, 0x18, 0x1e, 0x24, 0x00, 0x18, 0x1e, 0x25, 0x00, 0x19, 0x1e, 0x25, 0x00, 0x18, 0x1e, 0x26, 0x00, 0x19, 0x1f, 0x26, 0x00, 0x1a, 0x1f, 0x26, 0x00, 0x1a, 0x1f, 0x27, 0x00, 0x1a, 0x1f, 0x28, 0x00, 0x1a, 0x20, 0x26, 0x00, 0x19, 0x20, 0x27, 0x00, 0x1a, 0x20, 0x27, 0x00, 0x1a, 0x20, 0x28, 0x00, 0x1b, 0x20, 0x29, 0x00, 0x1b, 0x21, 0x28, 0x00, 0x1b, 0x21, 0x29, 0x00, 0x1c, 0x21, 0x2a, 0x00, 0x1d, 0x22, 0x29, 0x00, 0x1c, 0x22, 0x2a, 0x00, 0x1d, 0x22, 0x2a, 0x00, 0x1e, 0x23, 0x2c, 0x00, 0x1d, 0x24, 0x2b, 0x00, 0x1d, 0x24, 0x2c, 0x00, 0x1c, 0x24, 0x2d, 0x00, 0x1e, 0x25, 0x2d, 0x00, 0x1f, 0x25, 0x2e, 0x00, 0x1e, 0x26, 0x2e, 0x00, 0x1f, 0x26, 0x2e, 0x00, 0x1f, 0x26, 0x30, 0x00, 0x21, 0x27, 0x2e, 0x00, 0x20, 0x27, 0x2f, 0x00, 0x20, 0x27, 0x31, 0x00, 0x20, 0x29, 0x32, 0x00, 0x20, 0x29, 0x33, 0x00, 0x21, 0x2a, 0x33, 0x00, 0x24, 0x2c, 0x35, 0x00, 0x24, 0x2c, 0x38, 0x00, 0x26, 0x31, 0x3b, 0x00, 0x27, 0x31, 0x3b, 0x00, 0xff, 0x00, 0xff, 0x00, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x05, 0x1a, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x25, 0x48, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x4a, 0x54, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x8a, 0x8c, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x41, 0x5e, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x0d, 0x27, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x1b, 0x1f, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x00, 0x32, 0x69, 0x29, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x21, 0x38, 0x63, 0x2b, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x3d, 0x2b, 0x1c, 0x0e, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x5d, 0x7e, 0x2b, 0x08, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x5d, 0x80, 0x4d, 0x4c, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x24, 0x4a, 0x9c, 0xa1, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x10, 0x39, 0x76, 0x46, 0x6d, 0x9a, 0x60, 0x3f, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x01, 0x78, 0x8e, 0x32, 0x37, 0x81, 0x6c, 0x2a, 0x3c, 0x55, 0x2c, 0x1d, 0x2d, 0x17, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x06, 0x27, 0x55, 0x82, 0x9b, 0x45, 0x0e, 0x47, 0x61, 0x0f, 0x1a, 0x0f, 0x20, 0x62, 0x28, 0x0f, 0x18, 0x08, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x35, 0x1b, 0x40, 0x98, 0x4d, 0x18, 0x15, 0x1c, 0x26, 0x1b, 0x3b, 0x49, 0x20, 0x46, 0x67, 0x1b, 0x13, 0x0c, 0x15, 0x20, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x25, 0x4d, 0x3c, 0x34, 0x2b, 0x1c, 0x08, 0x0b, 0x0f, 0x1b, 0x32, 0x9e, 0x8a, 0x08, 0x27, 0x22, 0x0f, 0x36, 0x6f, 0x75, 0x3b, 0x39, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x7d, 0x7a, 0x56, 0x48, 0x68, 0x32, 0x06, 0xa3, 0xa3, 0xa3, 0x14, 0x40, 0x86, 0x6e, 0xa3, 0xa3, 0xa3, 0x06, 0x2d, 0x85, 0x92, 0x5b, 0x32, 0x6a, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x1c, 0x58, 0x8a, 0x65, 0x18, 0x21, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x07, 0x43, 0x83, 0x43, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x73, 0x91, 0x7f, 0x62, 0x20, 0x15, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x1e, 0x31, 0x0f, 0x2e, 0x1c, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x1b, 0x1b, 0x32, 0x16, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x43, 0x3b, 0x22, 0x55, 0x47, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x72, 0x9d, 0x60, 0x33, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x2d, 0x0f, 0x1b, 0x0f, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x11, 0x2d, 0x93, 0x55, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x50, 0x44, 0x90, 0x8a, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x3a, 0x77, 0x88, 0x47, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x25, 0x45, 0x25, 0x25, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x8a, 0x51, 0x23, 0x43, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x57, 0x5a, 0xa0, 0x84, 0x87, 0x74, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x02, 0x08, 0x8f, 0x8b, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x96, 0x6a, 0x41, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x4e, 0x95, 0x68, 0x5a, 0x4b, 0x7b, 0x70, 0x4c, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x04, 0x53, 0x8d, 0x79, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x79, 0x80, 0x5b, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x0e, 0x7c, 0x94, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x4f, 0x6a, 0x47, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x5f, 0x40, 0x1b, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x46, 0x2d, 0x08, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x97, 0x82, 0x18, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x58, 0x43, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x69, 0x5c, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x71, 0x40, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x65, 0x60, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x52, 0x2d, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x5e, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x2d, 0x20, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x6f, 0x6b, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x2b, 0x5b, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x2e, 0x44, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x25, 0x41, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x40, 0x1e, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x10, 0x38, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x69, 0x42, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x3b, 0x19, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x03, 0x20, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x53, 0x1d, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x4f, 0x15, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x1d, 0x09, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x48, 0x89, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x1e, 0x33, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x5b, 0x39, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x3b, 0x2a, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x59, 0x9f, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x33, 0x0a, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x2f, 0x64, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x1d, 0x2b, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x12, 0x99, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x49, 0x3e, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x1c, 0x36, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x30, 0x5e, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x8a, 0x48, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_mikmod.c����������������������������������������������������������������0000644�0000000�0000000�00000013230�12257265725�016023� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * tracker music (module file) decoding support using libmikmod * Copyright (C) 2013 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #include "quakedef.h" #if defined(USE_CODEC_MIKMOD) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_mikmod.h" #include <mikmod.h> #if ((LIBMIKMOD_VERSION+0) < 0x030105) #error libmikmod version is way too old and unusable. #endif #if (LIBMIKMOD_VERSION < 0x030107) /* ancient libmikmod */ #define S_MIKMOD_initlib(c) MikMod_Init() #else #define S_MIKMOD_initlib(c) MikMod_Init(c) #endif #ifndef DMODE_NOISEREDUCTION #define DMODE_NOISEREDUCTION 0x1000 /* Low pass filtering */ #endif #ifndef DMODE_SIMDMIXER #define DMODE_SIMDMIXER 0x0800 /* enable SIMD mixing */ #endif typedef struct _mik_priv { /* struct MREADER in libmikmod <= 3.2.0-beta2 * doesn't have iobase members. adding them here * so that if we compile against 3.2.0-beta2, we * can still run OK against 3.2.0b3 and newer. */ struct MREADER reader; long iobase, prev_iobase; fshandle_t *fh; MODULE *module; } mik_priv_t; static int MIK_Seek (MREADER *r, long ofs, int whence) { return FS_fseek(((mik_priv_t *)r)->fh, ofs, whence); } static long MIK_Tell (MREADER *r) { return FS_ftell(((mik_priv_t *)r)->fh); } static BOOL MIK_Read (MREADER *r, void *ptr, size_t siz) { return !!FS_fread(ptr, siz, 1, ((mik_priv_t *)r)->fh); } static int MIK_Get (MREADER *r) { return FS_fgetc(((mik_priv_t *)r)->fh); } static BOOL MIK_Eof (MREADER *r) { return FS_feof(((mik_priv_t *)r)->fh); } static qboolean S_MIKMOD_CodecInitialize (void) { if (mikmod_codec.initialized) return true; /* set mode flags to only we like: */ md_mode = 0; if ((shm->samplebits / 8) == 2) md_mode |= DMODE_16BITS; if (shm->channels == 2) md_mode |= DMODE_STEREO; md_mode |= DMODE_SOFT_MUSIC; /* this is a software-only mixer */ md_mode |= DMODE_HQMIXER; /* high-quality mixer is OK */ /* md_mixfreq is UWORD, so something like 96000 isn't OK */ md_mixfreq = (shm->speed < 65536)? shm->speed : 48000; /* keeping md_device as 0 which is default (auto-detect: we * only register drv_nos, and it will be the only one found.) * md_pansep (stereo channels separation) default 128 is OK. * no reverbation (md_reverb 0 (up to 15)) is OK. * md_musicvolume and md_sndfxvolume defaults are 128: OK. */ /* just tone down overall volume md_volume from 128 to 96? */ md_volume = 96; MikMod_RegisterDriver(&drv_nos); /* only need the "nosound" driver, none else */ MikMod_RegisterAllLoaders(); if (S_MIKMOD_initlib(NULL)) { Con_DPrintf("Could not initialize MikMod: %s\n", MikMod_strerror(MikMod_errno)); return false; } /* this can't get set with drv_nos, but whatever, be safe: */ md_mode &= ~DMODE_SIMDMIXER; /* SIMD mixer is buggy when combined with HQMIXER */ mikmod_codec.initialized = true; return true; } static void S_MIKMOD_CodecShutdown (void) { if (mikmod_codec.initialized) { mikmod_codec.initialized = false; MikMod_Exit(); } } static qboolean S_MIKMOD_CodecOpenStream (snd_stream_t *stream) { mik_priv_t *priv; stream->priv = Z_Malloc(sizeof(mik_priv_t)); priv = (mik_priv_t *) stream->priv; priv->reader.Seek = MIK_Seek; priv->reader.Tell = MIK_Tell; priv->reader.Read = MIK_Read; priv->reader.Get = MIK_Get; priv->reader.Eof = MIK_Eof; priv->fh = &stream->fh; priv->module = Player_LoadGeneric((MREADER *)stream->priv, 64, 0); if (!priv->module) { Con_DPrintf("Could not load module: %s\n", MikMod_strerror(MikMod_errno)); Z_Free(stream->priv); return false; } /* keep default values of fadeout (0: don't fade out volume during when last * position of the module is being played), extspd (1: do process Protracker * extended speed effect), panflag (1: do process panning effects), wrap (0: * don't wrap to restart position when module is finished) are OK with us as * set internally by libmikmod::Player_Init(). */ /* just change the loop setting to 0, i.e. don't process in-module loops: */ priv->module->loop = 0; Player_Start(priv->module); stream->info.rate = md_mixfreq; stream->info.bits = (md_mode & DMODE_16BITS)? 16: 8; stream->info.width = stream->info.bits / 8; stream->info.channels = (md_mode & DMODE_STEREO)? 2 : 1; /* Con_DPrintf("Playing %s (%d chn)\n", priv->module->songname, priv->module->numchn);*/ return true; } static int S_MIKMOD_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) { if (!Player_Active()) return 0; return (int) VC_WriteBytes((SBYTE *)buffer, bytes); } static void S_MIKMOD_CodecCloseStream (snd_stream_t *stream) { Player_Stop(); Player_Free(((mik_priv_t *)stream->priv)->module); Z_Free(stream->priv); S_CodecUtilClose(&stream); } static int S_MIKMOD_CodecRewindStream (snd_stream_t *stream) { Player_SetPosition (0); return 0; } snd_codec_t mikmod_codec = { CODECTYPE_MOD, false, "s3m", S_MIKMOD_CodecInitialize, S_MIKMOD_CodecShutdown, S_MIKMOD_CodecOpenStream, S_MIKMOD_CodecReadStream, S_MIKMOD_CodecRewindStream, S_MIKMOD_CodecCloseStream, NULL }; #endif /* USE_CODEC_MIKMOD */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/platform.h������������������������������������������������������������������0000644�0000000�0000000�00000002362�12407762022�015521� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_PLATFORM_H #define _QUAKE_PLATFORM_H /* platform dependent way to set the window icon */ void PL_SetWindowIcon(void); /* platform dependent cleanup */ void PL_VID_Shutdown (void); /* retrieve text from the clipboard (returns Z_Malloc()'ed data) */ char *PL_GetClipboardData (void); /* show an error dialog */ void PL_ErrorDialog(const char *text); #endif /* _QUAKE_PLATFORM_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cl_parse.c������������������������������������������������������������������0000644�0000000�0000000�00000071763�12530477523�015501� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cl_parse.c -- parse a message received from the server #include "quakedef.h" #include "bgmusic.h" const char *svc_strings[] = { "svc_bad", "svc_nop", "svc_disconnect", "svc_updatestat", "svc_version", // [long] server version "svc_setview", // [short] entity number "svc_sound", // <see code> "svc_time", // [float] server time "svc_print", // [string] null terminated string "svc_stufftext", // [string] stuffed into client's console buffer // the string should be \n terminated "svc_setangle", // [vec3] set the view angle to this absolute value "svc_serverinfo", // [long] version // [string] signon string // [string]..[0]model cache [string]...[0]sounds cache // [string]..[0]item cache "svc_lightstyle", // [byte] [string] "svc_updatename", // [byte] [string] "svc_updatefrags", // [byte] [short] "svc_clientdata", // <shortbits + data> "svc_stopsound", // <see code> "svc_updatecolors", // [byte] [byte] "svc_particle", // [vec3] <variable> "svc_damage", // [byte] impact [byte] blood [vec3] from "svc_spawnstatic", "OBSOLETE svc_spawnbinary", "svc_spawnbaseline", "svc_temp_entity", // <variable> "svc_setpause", "svc_signonnum", "svc_centerprint", "svc_killedmonster", "svc_foundsecret", "svc_spawnstaticsound", "svc_intermission", "svc_finale", // [string] music [string] text "svc_cdtrack", // [byte] track [byte] looptrack "svc_sellscreen", "svc_cutscene", //johnfitz -- new server messages "", // 35 "", // 36 "svc_skybox", // 37 // [string] skyname "", // 38 "", // 39 "svc_bf", // 40 // no data "svc_fog", // 41 // [byte] density [byte] red [byte] green [byte] blue [float] time "svc_spawnbaseline2", //42 // support for large modelindex, large framenum, alpha, using flags "svc_spawnstatic2", // 43 // support for large modelindex, large framenum, alpha, using flags "svc_spawnstaticsound2", // 44 // [coord3] [short] samp [byte] vol [byte] aten "", // 44 "", // 45 "", // 46 "", // 47 "", // 48 "", // 49 //johnfitz }; qboolean warn_about_nehahra_protocol; //johnfitz extern vec3_t v_punchangles[2]; //johnfitz //============================================================================= /* =============== CL_EntityNum This error checks and tracks the total number of entities =============== */ entity_t *CL_EntityNum (int num) { //johnfitz -- check minimum number too if (num < 0) Host_Error ("CL_EntityNum: %i is an invalid number",num); //john if (num >= cl.num_entities) { if (num >= cl_max_edicts) //johnfitz -- no more MAX_EDICTS Host_Error ("CL_EntityNum: %i is an invalid number",num); while (cl.num_entities<=num) { cl_entities[cl.num_entities].colormap = vid.colormap; cl_entities[cl.num_entities].lerpflags |= LERP_RESETMOVE|LERP_RESETANIM; //johnfitz cl.num_entities++; } } return &cl_entities[num]; } /* ================== CL_ParseStartSoundPacket ================== */ void CL_ParseStartSoundPacket(void) { vec3_t pos; int channel, ent; int sound_num; int volume; int field_mask; float attenuation; int i; field_mask = MSG_ReadByte(); if (field_mask & SND_VOLUME) volume = MSG_ReadByte (); else volume = DEFAULT_SOUND_PACKET_VOLUME; if (field_mask & SND_ATTENUATION) attenuation = MSG_ReadByte () / 64.0; else attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; //johnfitz -- PROTOCOL_FITZQUAKE if (field_mask & SND_LARGEENTITY) { ent = (unsigned short) MSG_ReadShort (); channel = MSG_ReadByte (); } else { channel = (unsigned short) MSG_ReadShort (); ent = channel >> 3; channel &= 7; } if (field_mask & SND_LARGESOUND) sound_num = (unsigned short) MSG_ReadShort (); else sound_num = MSG_ReadByte (); //johnfitz //johnfitz -- check soundnum if (sound_num >= MAX_SOUNDS) Host_Error ("CL_ParseStartSoundPacket: %i > MAX_SOUNDS", sound_num); //johnfitz if (ent > cl_max_edicts) //johnfitz -- no more MAX_EDICTS Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent); for (i = 0; i < 3; i++) pos[i] = MSG_ReadCoord (); S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation); } /* ================== CL_KeepaliveMessage When the client is taking a long time to load stuff, send keepalive messages so the server doesn't disconnect. ================== */ static byte net_olddata[NET_MAXMESSAGE]; void CL_KeepaliveMessage (void) { float time; static float lastmsg; int ret; sizebuf_t old; byte *olddata; if (sv.active) return; // no need if server is local if (cls.demoplayback) return; // read messages from server, should just be nops olddata = net_olddata; old = net_message; memcpy (olddata, net_message.data, net_message.cursize); do { ret = CL_GetMessage (); switch (ret) { default: Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed"); case 0: break; // nothing waiting case 1: Host_Error ("CL_KeepaliveMessage: received a message"); break; case 2: if (MSG_ReadByte() != svc_nop) Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop"); break; } } while (ret); net_message = old; memcpy (net_message.data, olddata, net_message.cursize); // check time time = Sys_DoubleTime (); if (time - lastmsg < 5) return; lastmsg = time; // write out a nop Con_Printf ("--> client to server keepalive\n"); MSG_WriteByte (&cls.message, clc_nop); NET_SendMessage (cls.netcon, &cls.message); SZ_Clear (&cls.message); } /* ================== CL_ParseServerInfo ================== */ void CL_ParseServerInfo (void) { const char *str; int i; int nummodels, numsounds; char model_precache[MAX_MODELS][MAX_QPATH]; char sound_precache[MAX_SOUNDS][MAX_QPATH]; Con_DPrintf ("Serverinfo packet received.\n"); // ericw -- bring up loading plaque for map changes within a demo. // it will be hidden in CL_SignonReply. if (cls.demoplayback) SCR_BeginLoadingPlaque(); // // wipe the client_state_t struct // CL_ClearState (); // parse protocol version number i = MSG_ReadLong (); //johnfitz -- support multiple protocols if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) { Con_Printf ("\n"); //because there's no newline after serverinfo print Host_Error ("Server returned version %i, not %i or %i", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); } cl.protocol = i; //johnfitz // parse maxclients cl.maxclients = MSG_ReadByte (); if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) { Host_Error ("Bad maxclients (%u) from server", cl.maxclients); } cl.scores = (scoreboard_t *) Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); // parse gametype cl.gametype = MSG_ReadByte (); // parse signon message str = MSG_ReadString (); q_strlcpy (cl.levelname, str, sizeof(cl.levelname)); // seperate the printfs so the server message can have a color Con_Printf ("\n%s\n", Con_Quakebar(40)); //johnfitz Con_Printf ("%c%s\n", 2, str); //johnfitz -- tell user which protocol this is Con_Printf ("Using protocol %i\n", i); // first we go through and touch all of the precache data that still // happens to be in the cache, so precaching something else doesn't // needlessly purge it // precache models memset (cl.model_precache, 0, sizeof(cl.model_precache)); for (nummodels = 1 ; ; nummodels++) { str = MSG_ReadString (); if (!str[0]) break; if (nummodels==MAX_MODELS) { Host_Error ("Server sent too many model precaches"); } q_strlcpy (model_precache[nummodels], str, MAX_QPATH); Mod_TouchModel (str); } //johnfitz -- check for excessive models if (nummodels >= 256) Con_DWarning ("%i models exceeds standard limit of 256.\n", nummodels); //johnfitz // precache sounds memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); for (numsounds = 1 ; ; numsounds++) { str = MSG_ReadString (); if (!str[0]) break; if (numsounds==MAX_SOUNDS) { Host_Error ("Server sent too many sound precaches"); } q_strlcpy (sound_precache[numsounds], str, MAX_QPATH); S_TouchSound (str); } //johnfitz -- check for excessive sounds if (numsounds >= 256) Con_DWarning ("%i sounds exceeds standard limit of 256.\n", numsounds); //johnfitz // // now we try to load everything else until a cache allocation fails // // copy the naked name of the map file to the cl structure -- O.S COM_StripExtension (COM_SkipPath(model_precache[1]), cl.mapname, sizeof(cl.mapname)); for (i = 1; i < nummodels; i++) { cl.model_precache[i] = Mod_ForName (model_precache[i], false); if (cl.model_precache[i] == NULL) { Host_Error ("Model %s not found", model_precache[i]); } CL_KeepaliveMessage (); } S_BeginPrecaching (); for (i = 1; i < numsounds; i++) { cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]); CL_KeepaliveMessage (); } S_EndPrecaching (); // local state cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; R_NewMap (); //johnfitz -- clear out string; we don't consider identical //messages to be duplicates if the map has changed in between con_lastcenterstring[0] = 0; //johnfitz Hunk_Check (); // make sure nothing is hurt noclip_anglehack = false; // noclip is turned off at start warn_about_nehahra_protocol = true; //johnfitz -- warn about nehahra protocol hack once per server connection //johnfitz -- reset developer stats memset(&dev_stats, 0, sizeof(dev_stats)); memset(&dev_peakstats, 0, sizeof(dev_peakstats)); memset(&dev_overflows, 0, sizeof(dev_overflows)); } /* ================== CL_ParseUpdate Parse an entity update message from the server If an entities model or origin changes from frame to frame, it must be relinked. Other attributes can change without relinking. ================== */ void CL_ParseUpdate (int bits) { int i; qmodel_t *model; int modnum; qboolean forcelink; entity_t *ent; int num; int skin; if (cls.signon == SIGNONS - 1) { // first update is the final signon stage cls.signon = SIGNONS; CL_SignonReply (); } if (bits & U_MOREBITS) { i = MSG_ReadByte (); bits |= (i<<8); } //johnfitz -- PROTOCOL_FITZQUAKE if (cl.protocol == PROTOCOL_FITZQUAKE) { if (bits & U_EXTEND1) bits |= MSG_ReadByte() << 16; if (bits & U_EXTEND2) bits |= MSG_ReadByte() << 24; } //johnfitz if (bits & U_LONGENTITY) num = MSG_ReadShort (); else num = MSG_ReadByte (); ent = CL_EntityNum (num); if (ent->msgtime != cl.mtime[1]) forcelink = true; // no previous frame to lerp from else forcelink = false; //johnfitz -- lerping if (ent->msgtime + 0.2 < cl.mtime[0]) //more than 0.2 seconds since the last message (most entities think every 0.1 sec) ent->lerpflags |= LERP_RESETANIM; //if we missed a think, we'd be lerping from the wrong frame //johnfitz ent->msgtime = cl.mtime[0]; if (bits & U_MODEL) { modnum = MSG_ReadByte (); if (modnum >= MAX_MODELS) Host_Error ("CL_ParseModel: bad modnum"); } else modnum = ent->baseline.modelindex; if (bits & U_FRAME) ent->frame = MSG_ReadByte (); else ent->frame = ent->baseline.frame; if (bits & U_COLORMAP) i = MSG_ReadByte(); else i = ent->baseline.colormap; if (!i) ent->colormap = vid.colormap; else { if (i > cl.maxclients) Sys_Error ("i >= cl.maxclients"); ent->colormap = cl.scores[i-1].translations; } if (bits & U_SKIN) skin = MSG_ReadByte(); else skin = ent->baseline.skin; if (skin != ent->skinnum) { ent->skinnum = skin; if (num > 0 && num <= cl.maxclients) R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin } if (bits & U_EFFECTS) ent->effects = MSG_ReadByte(); else ent->effects = ent->baseline.effects; // shift the known values for interpolation VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); if (bits & U_ORIGIN1) ent->msg_origins[0][0] = MSG_ReadCoord (); else ent->msg_origins[0][0] = ent->baseline.origin[0]; if (bits & U_ANGLE1) ent->msg_angles[0][0] = MSG_ReadAngle(); else ent->msg_angles[0][0] = ent->baseline.angles[0]; if (bits & U_ORIGIN2) ent->msg_origins[0][1] = MSG_ReadCoord (); else ent->msg_origins[0][1] = ent->baseline.origin[1]; if (bits & U_ANGLE2) ent->msg_angles[0][1] = MSG_ReadAngle(); else ent->msg_angles[0][1] = ent->baseline.angles[1]; if (bits & U_ORIGIN3) ent->msg_origins[0][2] = MSG_ReadCoord (); else ent->msg_origins[0][2] = ent->baseline.origin[2]; if (bits & U_ANGLE3) ent->msg_angles[0][2] = MSG_ReadAngle(); else ent->msg_angles[0][2] = ent->baseline.angles[2]; //johnfitz -- lerping for movetype_step entities if (bits & U_STEP) { ent->lerpflags |= LERP_MOVESTEP; ent->forcelink = true; } else ent->lerpflags &= ~LERP_MOVESTEP; //johnfitz //johnfitz -- PROTOCOL_FITZQUAKE and PROTOCOL_NEHAHRA if (cl.protocol == PROTOCOL_FITZQUAKE) { if (bits & U_ALPHA) ent->alpha = MSG_ReadByte(); else ent->alpha = ent->baseline.alpha; if (bits & U_FRAME2) ent->frame = (ent->frame & 0x00FF) | (MSG_ReadByte() << 8); if (bits & U_MODEL2) modnum = (modnum & 0x00FF) | (MSG_ReadByte() << 8); if (bits & U_LERPFINISH) { ent->lerpfinish = ent->msgtime + ((float)(MSG_ReadByte()) / 255); ent->lerpflags |= LERP_FINISH; } else ent->lerpflags &= ~LERP_FINISH; } else if (cl.protocol == PROTOCOL_NETQUAKE) { //HACK: if this bit is set, assume this is PROTOCOL_NEHAHRA if (bits & U_TRANS) { float a, b; if (warn_about_nehahra_protocol) { Con_Warning ("nonstandard update bit, assuming Nehahra protocol\n"); warn_about_nehahra_protocol = false; } a = MSG_ReadFloat(); b = MSG_ReadFloat(); //alpha if (a == 2) MSG_ReadFloat(); //fullbright (not using this yet) ent->alpha = ENTALPHA_ENCODE(b); } else ent->alpha = ent->baseline.alpha; } //johnfitz //johnfitz -- moved here from above model = cl.model_precache[modnum]; if (model != ent->model) { ent->model = model; // automatic animation (torches, etc) can be either all together // or randomized if (model) { if (model->synctype == ST_RAND) ent->syncbase = (float)(rand()&0x7fff) / 0x7fff; else ent->syncbase = 0.0; } else forcelink = true; // hack to make null model players work if (num > 0 && num <= cl.maxclients) R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin ent->lerpflags |= LERP_RESETANIM; //johnfitz -- don't lerp animation across model changes } //johnfitz if ( forcelink ) { // didn't have an update last message VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); VectorCopy (ent->msg_origins[0], ent->origin); VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); VectorCopy (ent->msg_angles[0], ent->angles); ent->forcelink = true; } } /* ================== CL_ParseBaseline ================== */ void CL_ParseBaseline (entity_t *ent, int version) //johnfitz -- added argument { int i; int bits; //johnfitz //johnfitz -- PROTOCOL_FITZQUAKE bits = (version == 2) ? MSG_ReadByte() : 0; ent->baseline.modelindex = (bits & B_LARGEMODEL) ? MSG_ReadShort() : MSG_ReadByte(); ent->baseline.frame = (bits & B_LARGEFRAME) ? MSG_ReadShort() : MSG_ReadByte(); //johnfitz ent->baseline.colormap = MSG_ReadByte(); ent->baseline.skin = MSG_ReadByte(); for (i = 0; i < 3; i++) { ent->baseline.origin[i] = MSG_ReadCoord (); ent->baseline.angles[i] = MSG_ReadAngle (); } ent->baseline.alpha = (bits & B_ALPHA) ? MSG_ReadByte() : ENTALPHA_DEFAULT; //johnfitz -- PROTOCOL_FITZQUAKE } /* ================== CL_ParseClientdata Server information pertaining to this client only ================== */ void CL_ParseClientdata (void) { int i, j; int bits; //johnfitz bits = (unsigned short)MSG_ReadShort (); //johnfitz -- read bits here isntead of in CL_ParseServerMessage() //johnfitz -- PROTOCOL_FITZQUAKE if (bits & SU_EXTEND1) bits |= (MSG_ReadByte() << 16); if (bits & SU_EXTEND2) bits |= (MSG_ReadByte() << 24); //johnfitz if (bits & SU_VIEWHEIGHT) cl.viewheight = MSG_ReadChar (); else cl.viewheight = DEFAULT_VIEWHEIGHT; if (bits & SU_IDEALPITCH) cl.idealpitch = MSG_ReadChar (); else cl.idealpitch = 0; VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); for (i = 0; i < 3; i++) { if (bits & (SU_PUNCH1<<i) ) cl.punchangle[i] = MSG_ReadChar(); else cl.punchangle[i] = 0; if (bits & (SU_VELOCITY1<<i) ) cl.mvelocity[0][i] = MSG_ReadChar()*16; else cl.mvelocity[0][i] = 0; } //johnfitz -- update v_punchangles if (v_punchangles[0][0] != cl.punchangle[0] || v_punchangles[0][1] != cl.punchangle[1] || v_punchangles[0][2] != cl.punchangle[2]) { VectorCopy (v_punchangles[0], v_punchangles[1]); VectorCopy (cl.punchangle, v_punchangles[0]); } //johnfitz // [always sent] if (bits & SU_ITEMS) i = MSG_ReadLong (); if (cl.items != i) { // set flash times Sbar_Changed (); for (j = 0; j < 32; j++) if ( (i & (1<<j)) && !(cl.items & (1<<j))) cl.item_gettime[j] = cl.time; cl.items = i; } cl.onground = (bits & SU_ONGROUND) != 0; cl.inwater = (bits & SU_INWATER) != 0; if (bits & SU_WEAPONFRAME) cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte (); else cl.stats[STAT_WEAPONFRAME] = 0; if (bits & SU_ARMOR) i = MSG_ReadByte (); else i = 0; if (cl.stats[STAT_ARMOR] != i) { cl.stats[STAT_ARMOR] = i; Sbar_Changed (); } if (bits & SU_WEAPON) i = MSG_ReadByte (); else i = 0; if (cl.stats[STAT_WEAPON] != i) { cl.stats[STAT_WEAPON] = i; Sbar_Changed (); } i = MSG_ReadShort (); if (cl.stats[STAT_HEALTH] != i) { cl.stats[STAT_HEALTH] = i; Sbar_Changed (); } i = MSG_ReadByte (); if (cl.stats[STAT_AMMO] != i) { cl.stats[STAT_AMMO] = i; Sbar_Changed (); } for (i = 0; i < 4; i++) { j = MSG_ReadByte (); if (cl.stats[STAT_SHELLS+i] != j) { cl.stats[STAT_SHELLS+i] = j; Sbar_Changed (); } } i = MSG_ReadByte (); if (standard_quake) { if (cl.stats[STAT_ACTIVEWEAPON] != i) { cl.stats[STAT_ACTIVEWEAPON] = i; Sbar_Changed (); } } else { if (cl.stats[STAT_ACTIVEWEAPON] != (1<<i)) { cl.stats[STAT_ACTIVEWEAPON] = (1<<i); Sbar_Changed (); } } //johnfitz -- PROTOCOL_FITZQUAKE if (bits & SU_WEAPON2) cl.stats[STAT_WEAPON] |= (MSG_ReadByte() << 8); if (bits & SU_ARMOR2) cl.stats[STAT_ARMOR] |= (MSG_ReadByte() << 8); if (bits & SU_AMMO2) cl.stats[STAT_AMMO] |= (MSG_ReadByte() << 8); if (bits & SU_SHELLS2) cl.stats[STAT_SHELLS] |= (MSG_ReadByte() << 8); if (bits & SU_NAILS2) cl.stats[STAT_NAILS] |= (MSG_ReadByte() << 8); if (bits & SU_ROCKETS2) cl.stats[STAT_ROCKETS] |= (MSG_ReadByte() << 8); if (bits & SU_CELLS2) cl.stats[STAT_CELLS] |= (MSG_ReadByte() << 8); if (bits & SU_WEAPONFRAME2) cl.stats[STAT_WEAPONFRAME] |= (MSG_ReadByte() << 8); if (bits & SU_WEAPONALPHA) cl.viewent.alpha = MSG_ReadByte(); else cl.viewent.alpha = ENTALPHA_DEFAULT; //johnfitz //johnfitz -- lerping //ericw -- this was done before the upper 8 bits of cl.stats[STAT_WEAPON] were filled in, breaking on large maps like zendar.bsp if (cl.viewent.model != cl.model_precache[cl.stats[STAT_WEAPON]]) { cl.viewent.lerpflags |= LERP_RESETANIM; //don't lerp animation across model changes } //johnfitz } /* ===================== CL_NewTranslation ===================== */ void CL_NewTranslation (int slot) { int i, j; int top, bottom; byte *dest, *source; if (slot > cl.maxclients) Sys_Error ("CL_NewTranslation: slot > cl.maxclients"); dest = cl.scores[slot].translations; source = vid.colormap; memcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations)); top = cl.scores[slot].colors & 0xf0; bottom = (cl.scores[slot].colors &15)<<4; R_TranslatePlayerSkin (slot); for (i = 0; i < VID_GRADES; i++, dest += 256, source+=256) { if (top < 128) // the artists made some backwards ranges. sigh. memcpy (dest + TOP_RANGE, source + top, 16); else { for (j = 0; j < 16; j++) dest[TOP_RANGE+j] = source[top+15-j]; } if (bottom < 128) memcpy (dest + BOTTOM_RANGE, source + bottom, 16); else { for (j = 0; j < 16; j++) dest[BOTTOM_RANGE+j] = source[bottom+15-j]; } } } /* ===================== CL_ParseStatic ===================== */ void CL_ParseStatic (int version) //johnfitz -- added a parameter { entity_t *ent; int i; i = cl.num_statics; if (i >= MAX_STATIC_ENTITIES) Host_Error ("Too many static entities"); ent = &cl_static_entities[i]; cl.num_statics++; CL_ParseBaseline (ent, version); //johnfitz -- added second parameter // copy it to the current state ent->model = cl.model_precache[ent->baseline.modelindex]; ent->lerpflags |= LERP_RESETANIM; //johnfitz -- lerping ent->frame = ent->baseline.frame; ent->colormap = vid.colormap; ent->skinnum = ent->baseline.skin; ent->effects = ent->baseline.effects; ent->alpha = ent->baseline.alpha; //johnfitz -- alpha VectorCopy (ent->baseline.origin, ent->origin); VectorCopy (ent->baseline.angles, ent->angles); R_AddEfrags (ent); } /* =================== CL_ParseStaticSound =================== */ void CL_ParseStaticSound (int version) //johnfitz -- added argument { vec3_t org; int sound_num, vol, atten; int i; for (i = 0; i < 3; i++) org[i] = MSG_ReadCoord (); //johnfitz -- PROTOCOL_FITZQUAKE if (version == 2) sound_num = MSG_ReadShort (); else sound_num = MSG_ReadByte (); //johnfitz vol = MSG_ReadByte (); atten = MSG_ReadByte (); S_StaticSound (cl.sound_precache[sound_num], org, vol, atten); } #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); /* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i; const char *str; //johnfitz int total, j, lastcmd; //johnfitz // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf ("%i ",net_message.cursize); else if (cl_shownet.value == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); lastcmd = 0; while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & U_SIGNAL) //johnfitz -- was 128, changed for clarity { SHOWNET("fast update"); CL_ParseUpdate (cmd&127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("Illegible server message, previous was %s", svc_strings[lastcmd]); //johnfitz -- added svc_strings[lastcmd] break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: CL_ParseClientdata (); //johnfitz -- removed bits parameter, we will read this inside CL_ParseClientdata() break; case svc_version: i = MSG_ReadLong (); //johnfitz -- support multiple protocols if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) Host_Error ("Server returned version %i, not %i or %i", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); cl.protocol = i; //johnfitz break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); case svc_print: Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_stufftext: Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); q_strlcpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING); cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); //johnfitz -- save extra info if (cl_lightstyle[i].length) { total = 0; cl_lightstyle[i].peak = 'a'; for (j=0; j<cl_lightstyle[i].length; j++) { total += cl_lightstyle[i].map[j] - 'a'; cl_lightstyle[i].peak = q_max(cl_lightstyle[i].peak, cl_lightstyle[i].map[j]); } cl_lightstyle[i].average = total / cl_lightstyle[i].length + 'a'; } else cl_lightstyle[i].average = cl_lightstyle[i].peak = 'm'; //johnfitz break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); q_strlcpy (cl.scores[i].name, MSG_ReadString(), MAX_SCOREBOARDNAME); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); cl.scores[i].frags = MSG_ReadShort (); break; case svc_updatecolors: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i), 1); // johnfitz -- added second parameter break; case svc_spawnstatic: CL_ParseStatic (1); //johnfitz -- added parameter break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); BGM_Pause (); } else { CDAudio_Resume (); BGM_Resume (); } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; //johnfitz -- if signonnum==2, signon packet has been fully parsed, so check for excessive static ents and efrags if (i == 2) { if (cl.num_statics > 128) Con_DWarning ("%i static entities exceeds standard limit of 128.\n", cl.num_statics); R_CheckEfrags (); } //johnfitz CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (1); //johnfitz -- added parameter break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) BGM_PlayCDtrack ((byte)cls.forcetrack, true); else BGM_PlayCDtrack ((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_sellscreen: Cmd_ExecuteString ("help", src_command); break; //johnfitz -- new svc types case svc_skybox: Sky_LoadSkyBox (MSG_ReadString()); break; case svc_bf: Cmd_ExecuteString ("bf", src_command); break; case svc_fog: Fog_ParseServerMessage (); break; case svc_spawnbaseline2: //PROTOCOL_FITZQUAKE i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i), 2); break; case svc_spawnstatic2: //PROTOCOL_FITZQUAKE CL_ParseStatic (2); break; case svc_spawnstaticsound2: //PROTOCOL_FITZQUAKE CL_ParseStaticSound (2); break; //johnfitz } lastcmd = cmd; //johnfitz } } �������������quakespasm-0.91.0/Quake/arch_def.h������������������������������������������������������������������0000644�0000000�0000000�00000011252�12357706347�015442� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * arch_def.h * platform specific definitions * - standalone header * - doesn't and must not include any other headers * - shouldn't depend on compiler.h, q_stdinc.h, or * any other headers * * Copyright (C) 2007-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #ifndef __ARCH_DEFS__ #define __ARCH_DEFS__ #if defined(__DJGPP__) || defined(MSDOS) || defined(__MSDOS__) || defined(__DOS__) # if !defined(PLATFORM_DOS) # define PLATFORM_DOS 1 # endif #elif defined(__OS2__) || defined(__EMX__) # if !defined(PLATFORM_OS2) # define PLATFORM_OS2 1 # endif #elif defined(_WIN32) || defined(_WIN64) # if !defined(PLATFORM_WINDOWS) # define PLATFORM_WINDOWS 1 # endif #elif defined(__APPLE__) && defined(__MACH__) /* Mac OS X */ # if !defined(PLATFORM_OSX) # define PLATFORM_OSX 1 # endif #elif defined(macintosh) /* Mac OS classic */ # if !defined(PLATFORM_MAC) # define PLATFORM_MAC 1 # endif #elif defined(__MORPHOS__) || defined(__AROS__) || defined(AMIGAOS) || \ defined(__amigaos__) || defined(__amigados__) || \ defined(AMIGA) || defined(_AMIGA) || defined(__AMIGA__) # if !defined(PLATFORM_AMIGA) # define PLATFORM_AMIGA 1 # endif #elif defined(__riscos__) # if !defined(PLATFORM_RISCOS) # define PLATFORM_RISCOS 1 # endif #else /* here goes the unix platforms */ #if defined(__unix) || defined(__unix__) || defined(unix) || \ defined(__linux__) || defined(__linux) || \ defined(__FreeBSD__) || defined(__DragonFly__) || \ defined(__FreeBSD_kernel__) /* Debian GNU/kFreeBSD */ || \ defined(__OpenBSD__) || defined(__NetBSD__) || \ defined(__hpux) || defined(__hpux__) || defined(_hpux) || \ defined(__sun) || defined(sun) || \ defined(__sgi) || defined(sgi) || defined(__sgi__) || \ defined(__GNU__) /* GNU/Hurd */ || \ defined(__QNX__) || defined(__QNXNTO__) # if !defined(PLATFORM_UNIX) # define PLATFORM_UNIX 1 # endif #endif #endif /* PLATFORM_xxx */ #if defined (PLATFORM_OSX) /* OS X is unix-based */ # if !defined(PLATFORM_UNIX) # define PLATFORM_UNIX 2 # endif #endif /* OS X -> PLATFORM_UNIX */ #if defined(__FreeBSD__) || defined(__DragonFly__) || \ defined(__FreeBSD_kernel__) /* Debian GNU/kFreeBSD */ || \ defined(__OpenBSD__) || defined(__NetBSD__) # if !defined(PLATFORM_BSD) # define PLATFORM_BSD 1 # endif #endif /* PLATFORM_BSD (for convenience) */ #if defined(_WIN64) # define PLATFORM_STRING "Win64" #elif defined(_WIN32) # define PLATFORM_STRING "Windows" #elif defined(PLATFORM_DOS) # define PLATFORM_STRING "DOS" #elif defined(PLATFORM_OS2) # define PLATFORM_STRING "OS/2" #elif defined(__linux__) || defined(__linux) # define PLATFORM_STRING "Linux" #elif defined(__DragonFly__) # define PLATFORM_STRING "DragonFly" #elif defined(__FreeBSD__) # define PLATFORM_STRING "FreeBSD" #elif defined(__NetBSD__) # define PLATFORM_STRING "NetBSD" #elif defined(__OpenBSD__) # define PLATFORM_STRING "OpenBSD" #elif defined(__MORPHOS__) # define PLATFORM_STRING "MorphOS" #elif defined(__AROS__) # define PLATFORM_STRING "AROS" #elif defined(PLATFORM_AMIGA) # define PLATFORM_STRING "AmigaOS" #elif defined(__QNX__) || defined(__QNXNTO__) # define PLATFORM_STRING "QNX" #elif defined(PLATFORM_OSX) # define PLATFORM_STRING "MacOSX" #elif defined(PLATFORM_MAC) # define PLATFORM_STRING "MacOS" #elif defined(__hpux) || defined(__hpux__) || defined(_hpux) # define PLATFORM_STRING "HP-UX" #elif (defined(__sun) || defined(sun)) && (defined(__svr4__) || defined(__SVR4)) # define PLATFORM_STRING "Solaris" #elif defined(__sun) || defined(sun) # define PLATFORM_STRING "SunOS" #elif defined(__sgi) || defined(sgi) || defined(__sgi__) # define PLATFORM_STRING "Irix" #elif defined(PLATFORM_RISCOS) # define PLATFORM_STRING "RiscOS" #elif defined(__GNU__) # define PLATFORM_STRING "GNU/Hurd" #elif defined(PLATFORM_UNIX) # define PLATFORM_STRING "Unix" #else # define PLATFORM_STRING "Unknown" # warning "Platform is UNKNOWN." #endif /* PLATFORM_STRING */ #endif /* __ARCH_DEFS__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_vorbis.c����������������������������������������������������������������0000644�0000000�0000000�00000011757�12424476246�016061� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Ogg/Vorbis streaming music support, loosely based on several open source * Quake engine based projects with many modifications. * * Copyright (C) 2010-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #include "quakedef.h" #if defined(USE_CODEC_VORBIS) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_vorbis.h" #define OV_EXCLUDE_STATIC_CALLBACKS #if defined(VORBIS_USE_TREMOR) /* for Tremor / Vorbisfile api differences, * see doc/diff.html in the Tremor package. */ #include <tremor/ivorbisfile.h> #else #include <vorbis/vorbisfile.h> #endif /* Vorbis codec can return the samples in a number of different * formats, we use the standard signed short format. */ #define VORBIS_SAMPLEBITS 16 #define VORBIS_SAMPLEWIDTH 2 #define VORBIS_SIGNED_DATA 1 /* CALLBACK FUNCTIONS: */ static int ovc_fclose (void *f) { return 0; /* we fclose() elsewhere. */ } static int ovc_fseek (void *f, ogg_int64_t off, int whence) { if (f == NULL) return (-1); return FS_fseek((fshandle_t *)f, (long) off, whence); } static ov_callbacks ovc_qfs = { (size_t (*)(void *, size_t, size_t, void *)) FS_fread, (int (*)(void *, ogg_int64_t, int)) ovc_fseek, (int (*)(void *)) ovc_fclose, (long (*)(void *)) FS_ftell }; #define OV_OPEN_CALLBACKS ov_open_callbacks static qboolean S_VORBIS_CodecInitialize (void) { return true; } static void S_VORBIS_CodecShutdown (void) { } static qboolean S_VORBIS_CodecOpenStream (snd_stream_t *stream) { OggVorbis_File *ovFile; vorbis_info *ovf_info; long numstreams; int res; ovFile = (OggVorbis_File *) Z_Malloc(sizeof(OggVorbis_File)); stream->priv = ovFile; res = OV_OPEN_CALLBACKS(&stream->fh, ovFile, NULL, 0, ovc_qfs); if (res != 0) { Con_Printf("%s is not a valid Ogg Vorbis file (error %i).\n", stream->name, res); goto _fail; } if (!ov_seekable(ovFile)) { Con_Printf("Stream %s not seekable.\n", stream->name); goto _fail; } ovf_info = ov_info(ovFile, 0); if (!ovf_info) { Con_Printf("Unable to get stream info for %s.\n", stream->name); goto _fail; } /* FIXME: handle section changes */ numstreams = ov_streams(ovFile); if (numstreams != 1) { Con_Printf("More than one (%ld) stream in %s.\n", numstreams, stream->name); goto _fail; } if (ovf_info->channels != 1 && ovf_info->channels != 2) { Con_Printf("Unsupported number of channels %d in %s\n", ovf_info->channels, stream->name); goto _fail; } stream->info.rate = ovf_info->rate; stream->info.channels = ovf_info->channels; stream->info.bits = VORBIS_SAMPLEBITS; stream->info.width = VORBIS_SAMPLEWIDTH; return true; _fail: if (res == 0) ov_clear(ovFile); Z_Free(ovFile); return false; } static int S_VORBIS_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) { int section; /* FIXME: handle section changes */ int cnt, res, rem; char * ptr; cnt = 0; rem = bytes; ptr = (char *) buffer; while (1) { /* # ov_read() from libvorbisfile returns the decoded PCM audio * in requested endianness, signedness and word size. * # ov_read() from Tremor (libvorbisidec) returns decoded audio * always in host-endian, signed 16 bit PCM format. * # For both of the libraries, if the audio is multichannel, * the channels are interleaved in the output buffer. */ res = ov_read( (OggVorbis_File *)stream->priv, ptr, rem, #if !defined(VORBIS_USE_TREMOR) host_bigendian, VORBIS_SAMPLEWIDTH, VORBIS_SIGNED_DATA, #endif /* ! VORBIS_USE_TREMOR */ §ion ); if (res <= 0) break; rem -= res; cnt += res; if (rem <= 0) break; ptr += res; } if (res < 0) return res; return cnt; } static void S_VORBIS_CodecCloseStream (snd_stream_t *stream) { ov_clear((OggVorbis_File *)stream->priv); Z_Free(stream->priv); S_CodecUtilClose(&stream); } static int S_VORBIS_CodecRewindStream (snd_stream_t *stream) { /* for libvorbisfile, the ov_time_seek() position argument * is seconds as doubles, whereas for Tremor libvorbisidec * it is milliseconds as 64 bit integers. */ return ov_time_seek ((OggVorbis_File *)stream->priv, 0); } snd_codec_t vorbis_codec = { CODECTYPE_VORBIS, true, /* always available. */ "ogg", S_VORBIS_CodecInitialize, S_VORBIS_CodecShutdown, S_VORBIS_CodecOpenStream, S_VORBIS_CodecReadStream, S_VORBIS_CodecRewindStream, S_VORBIS_CodecCloseStream, NULL }; #endif /* USE_CODEC_VORBIS */ �����������������quakespasm-0.91.0/Quake/cmd.c�����������������������������������������������������������������������0000644�0000000�0000000�00000034472�12566314317�014450� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cmd.c -- Quake script command processing module #include "quakedef.h" void Cmd_ForwardToServer (void); #define MAX_ALIAS_NAME 32 #define CMDLINE_LENGTH 256 //johnfitz -- mirrored in common.c typedef struct cmdalias_s { struct cmdalias_s *next; char name[MAX_ALIAS_NAME]; char *value; } cmdalias_t; cmdalias_t *cmd_alias; qboolean cmd_wait; //============================================================================= /* ============ Cmd_Wait_f Causes execution of the remainder of the command buffer to be delayed until next frame. This allows commands like: bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" ============ */ void Cmd_Wait_f (void) { cmd_wait = true; } /* ============================================================================= COMMAND BUFFER ============================================================================= */ sizebuf_t cmd_text; /* ============ Cbuf_Init ============ */ void Cbuf_Init (void) { SZ_Alloc (&cmd_text, 8192); // space for commands and script files } /* ============ Cbuf_AddText Adds command text at the end of the buffer ============ */ void Cbuf_AddText (const char *text) { int l; l = Q_strlen (text); if (cmd_text.cursize + l >= cmd_text.maxsize) { Con_Printf ("Cbuf_AddText: overflow\n"); return; } SZ_Write (&cmd_text, text, Q_strlen (text)); } /* ============ Cbuf_InsertText Adds command text immediately after the current command Adds a \n to the text FIXME: actually change the command buffer to do less copying ============ */ void Cbuf_InsertText (const char *text) { char *temp; int templen; // copy off any commands still remaining in the exec buffer templen = cmd_text.cursize; if (templen) { temp = (char *) Z_Malloc (templen); Q_memcpy (temp, cmd_text.data, templen); SZ_Clear (&cmd_text); } else temp = NULL; // shut up compiler // add the entire text of the file Cbuf_AddText (text); SZ_Write (&cmd_text, "\n", 1); // add the copied off data if (templen) { SZ_Write (&cmd_text, temp, templen); Z_Free (temp); } } /* ============ Cbuf_Execute ============ */ void Cbuf_Execute (void) { int i; char *text; char line[1024]; int quotes; while (cmd_text.cursize) { // find a \n or ; line break text = (char *)cmd_text.data; quotes = 0; for (i=0 ; i< cmd_text.cursize ; i++) { if (text[i] == '"') quotes++; if ( !(quotes&1) && text[i] == ';') break; // don't break if inside a quoted string if (text[i] == '\n') break; } if (i > (int)sizeof(line) - 1) { memcpy (line, text, sizeof(line) - 1); line[sizeof(line) - 1] = 0; } else { memcpy (line, text, i); line[i] = 0; } // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec, alias) can insert data at the // beginning of the text buffer if (i == cmd_text.cursize) cmd_text.cursize = 0; else { i++; cmd_text.cursize -= i; memmove (text, text + i, cmd_text.cursize); } // execute the command line Cmd_ExecuteString (line, src_command); if (cmd_wait) { // skip out while text still remains in buffer, leaving it // for next frame cmd_wait = false; break; } } } /* ============================================================================== SCRIPT COMMANDS ============================================================================== */ /* =============== Cmd_StuffCmds_f -- johnfitz -- rewritten to read the "cmdline" cvar, for use with dynamic mod loading Adds command line parameters as script statements Commands lead with a +, and continue until a - or another + quake +prog jctest.qp +cmd amlev1 quake -nosound +cmd amlev1 =============== */ void Cmd_StuffCmds_f (void) { extern cvar_t cmdline; char cmds[CMDLINE_LENGTH]; int i, j, plus; plus = false; // On Unix, argv[0] is command name for (i = 0, j = 0; cmdline.string[i]; i++) { if (cmdline.string[i] == '+') { plus = true; if (j > 0) { cmds[j-1] = ';'; cmds[j++] = ' '; } } else if (cmdline.string[i] == '-' && (i==0 || cmdline.string[i-1] == ' ')) //johnfitz -- allow hypenated map names with +map plus = false; else if (plus) cmds[j++] = cmdline.string[i]; } cmds[j] = 0; Cbuf_InsertText (cmds); } /* =============== Cmd_Exec_f =============== */ void Cmd_Exec_f (void) { char *f; int mark; if (Cmd_Argc () != 2) { Con_Printf ("exec <filename> : execute a script file\n"); return; } mark = Hunk_LowMark (); f = (char *)COM_LoadHunkFile (Cmd_Argv(1), NULL); if (!f) { Con_Printf ("couldn't exec %s\n",Cmd_Argv(1)); return; } Con_Printf ("execing %s\n",Cmd_Argv(1)); Cbuf_InsertText (f); Hunk_FreeToLowMark (mark); } /* =============== Cmd_Echo_f Just prints the rest of the line to the console =============== */ void Cmd_Echo_f (void) { int i; for (i=1 ; i<Cmd_Argc() ; i++) Con_Printf ("%s ",Cmd_Argv(i)); Con_Printf ("\n"); } /* =============== Cmd_Alias_f -- johnfitz -- rewritten Creates a new command that executes a command string (possibly ; seperated) =============== */ void Cmd_Alias_f (void) { cmdalias_t *a; char cmd[1024]; int i, c; const char *s; switch (Cmd_Argc()) { case 1: //list all aliases for (a = cmd_alias, i = 0; a; a=a->next, i++) Con_SafePrintf (" %s: %s", a->name, a->value); if (i) Con_SafePrintf ("%i alias command(s)\n", i); else Con_SafePrintf ("no alias commands found\n"); break; case 2: //output current alias string for (a = cmd_alias ; a ; a=a->next) if (!strcmp(Cmd_Argv(1), a->name)) Con_Printf (" %s: %s", a->name, a->value); break; default: //set alias string s = Cmd_Argv(1); if (strlen(s) >= MAX_ALIAS_NAME) { Con_Printf ("Alias name is too long\n"); return; } // if the alias allready exists, reuse it for (a = cmd_alias ; a ; a=a->next) { if (!strcmp(s, a->name)) { Z_Free (a->value); break; } } if (!a) { a = (cmdalias_t *) Z_Malloc (sizeof(cmdalias_t)); a->next = cmd_alias; cmd_alias = a; } strcpy (a->name, s); // copy the rest of the command line cmd[0] = 0; // start out with a null string c = Cmd_Argc(); for (i = 2; i < c; i++) { q_strlcat (cmd, Cmd_Argv(i), sizeof(cmd)); if (i != c - 1) q_strlcat (cmd, " ", sizeof(cmd)); } if (q_strlcat(cmd, "\n", sizeof(cmd)) >= sizeof(cmd)) { Con_Printf("alias value too long!\n"); cmd[0] = '\n'; // nullify the string cmd[1] = 0; } a->value = Z_Strdup (cmd); break; } } /* =============== Cmd_Unalias_f -- johnfitz =============== */ void Cmd_Unalias_f (void) { cmdalias_t *a, *prev; switch (Cmd_Argc()) { default: case 1: Con_Printf("unalias <name> : delete alias\n"); break; case 2: prev = NULL; for (a = cmd_alias; a; a = a->next) { if (!strcmp(Cmd_Argv(1), a->name)) { if (prev) prev->next = a->next; else cmd_alias = a->next; Z_Free (a->value); Z_Free (a); return; } prev = a; } Con_Printf ("No alias named %s\n", Cmd_Argv(1)); break; } } /* =============== Cmd_Unaliasall_f -- johnfitz =============== */ void Cmd_Unaliasall_f (void) { cmdalias_t *blah; while (cmd_alias) { blah = cmd_alias->next; Z_Free(cmd_alias->value); Z_Free(cmd_alias); cmd_alias = blah; } } /* ============================================================================= COMMAND EXECUTION ============================================================================= */ typedef struct cmd_function_s { struct cmd_function_s *next; const char *name; xcommand_t function; } cmd_function_t; #define MAX_ARGS 80 static int cmd_argc; static char *cmd_argv[MAX_ARGS]; static char cmd_null_string[] = ""; static const char *cmd_args = NULL; cmd_source_t cmd_source; //johnfitz -- better tab completion //static cmd_function_t *cmd_functions; // possible commands to execute cmd_function_t *cmd_functions; // possible commands to execute //johnfitz /* ============ Cmd_List_f -- johnfitz ============ */ void Cmd_List_f (void) { cmd_function_t *cmd; const char *partial; int len, count; if (Cmd_Argc() > 1) { partial = Cmd_Argv (1); len = Q_strlen(partial); } else { partial = NULL; len = 0; } count=0; for (cmd=cmd_functions ; cmd ; cmd=cmd->next) { if (partial && Q_strncmp (partial,cmd->name, len)) { continue; } Con_SafePrintf (" %s\n", cmd->name); count++; } Con_SafePrintf ("%i commands", count); if (partial) { Con_SafePrintf (" beginning with \"%s\"", partial); } Con_SafePrintf ("\n"); } /* ============ Cmd_Init ============ */ void Cmd_Init (void) { Cmd_AddCommand ("cmdlist", Cmd_List_f); //johnfitz Cmd_AddCommand ("unalias", Cmd_Unalias_f); //johnfitz Cmd_AddCommand ("unaliasall", Cmd_Unaliasall_f); //johnfitz Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f); Cmd_AddCommand ("exec",Cmd_Exec_f); Cmd_AddCommand ("echo",Cmd_Echo_f); Cmd_AddCommand ("alias",Cmd_Alias_f); Cmd_AddCommand ("cmd", Cmd_ForwardToServer); Cmd_AddCommand ("wait", Cmd_Wait_f); } /* ============ Cmd_Argc ============ */ int Cmd_Argc (void) { return cmd_argc; } /* ============ Cmd_Argv ============ */ const char *Cmd_Argv (int arg) { if (arg < 0 || arg >= cmd_argc) return cmd_null_string; return cmd_argv[arg]; } /* ============ Cmd_Args ============ */ const char *Cmd_Args (void) { return cmd_args; } /* ============ Cmd_TokenizeString Parses the given string into command line tokens. ============ */ void Cmd_TokenizeString (const char *text) { int i; // clear the args from the last string for (i=0 ; i<cmd_argc ; i++) Z_Free (cmd_argv[i]); cmd_argc = 0; cmd_args = NULL; while (1) { // skip whitespace up to a /n while (*text && *text <= ' ' && *text != '\n') { text++; } if (*text == '\n') { // a newline seperates commands in the buffer text++; break; } if (!*text) return; if (cmd_argc == 1) cmd_args = text; text = COM_Parse (text); if (!text) return; if (cmd_argc < MAX_ARGS) { cmd_argv[cmd_argc] = Z_Strdup (com_token); cmd_argc++; } } } /* ============ Cmd_AddCommand ============ */ void Cmd_AddCommand (const char *cmd_name, xcommand_t function) { cmd_function_t *cmd; cmd_function_t *cursor,*prev; //johnfitz -- sorted list insert if (host_initialized) // because hunk allocation would get stomped Sys_Error ("Cmd_AddCommand after host_initialized"); // fail if the command is a variable name if (Cvar_VariableString(cmd_name)[0]) { Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name); return; } // fail if the command already exists for (cmd=cmd_functions ; cmd ; cmd=cmd->next) { if (!Q_strcmp (cmd_name, cmd->name)) { Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name); return; } } cmd = (cmd_function_t *) Hunk_Alloc (sizeof(cmd_function_t)); cmd->name = cmd_name; cmd->function = function; //johnfitz -- insert each entry in alphabetical order if (cmd_functions == NULL || strcmp(cmd->name, cmd_functions->name) < 0) //insert at front { cmd->next = cmd_functions; cmd_functions = cmd; } else //insert later { prev = cmd_functions; cursor = cmd_functions->next; while ((cursor != NULL) && (strcmp(cmd->name, cursor->name) > 0)) { prev = cursor; cursor = cursor->next; } cmd->next = prev->next; prev->next = cmd; } //johnfitz } /* ============ Cmd_Exists ============ */ qboolean Cmd_Exists (const char *cmd_name) { cmd_function_t *cmd; for (cmd=cmd_functions ; cmd ; cmd=cmd->next) { if (!Q_strcmp (cmd_name,cmd->name)) return true; } return false; } /* ============ Cmd_CompleteCommand ============ */ const char *Cmd_CompleteCommand (const char *partial) { cmd_function_t *cmd; int len; len = Q_strlen(partial); if (!len) return NULL; // check functions for (cmd=cmd_functions ; cmd ; cmd=cmd->next) if (!Q_strncmp (partial,cmd->name, len)) return cmd->name; return NULL; } /* ============ Cmd_ExecuteString A complete command line has been parsed, so try to execute it FIXME: lookupnoadd the token to speed search? ============ */ void Cmd_ExecuteString (const char *text, cmd_source_t src) { cmd_function_t *cmd; cmdalias_t *a; cmd_source = src; Cmd_TokenizeString (text); // execute the command line if (!Cmd_Argc()) return; // no tokens // check functions for (cmd=cmd_functions ; cmd ; cmd=cmd->next) { if (!q_strcasecmp (cmd_argv[0],cmd->name)) { cmd->function (); return; } } // check alias for (a=cmd_alias ; a ; a=a->next) { if (!q_strcasecmp (cmd_argv[0], a->name)) { Cbuf_InsertText (a->value); return; } } // check cvars if (!Cvar_Command ()) Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0)); } /* =================== Cmd_ForwardToServer Sends the entire command line over to the server =================== */ void Cmd_ForwardToServer (void) { if (cls.state != ca_connected) { Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); return; } if (cls.demoplayback) return; // not really connected MSG_WriteByte (&cls.message, clc_stringcmd); if (q_strcasecmp(Cmd_Argv(0), "cmd") != 0) { SZ_Print (&cls.message, Cmd_Argv(0)); SZ_Print (&cls.message, " "); } if (Cmd_Argc() > 1) SZ_Print (&cls.message, Cmd_Args()); else SZ_Print (&cls.message, "\n"); } /* ================ Cmd_CheckParm Returns the position (1 to argc-1) in the command's argument list where the given parameter apears, or 0 if not present ================ */ int Cmd_CheckParm (const char *parm) { int i; if (!parm) Sys_Error ("Cmd_CheckParm: NULL"); for (i = 1; i < Cmd_Argc (); i++) if (! q_strcasecmp (parm, Cmd_Argv (i))) return i; return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/zone.c����������������������������������������������������������������������0000644�0000000�0000000�00000050722�12644413102�014641� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // zone.c #include "quakedef.h" #define DYNAMIC_SIZE (4 * 1024 * 1024) // ericw -- was 512KB (64-bit) / 384KB (32-bit) #define ZONEID 0x1d4a11 #define MINFRAGMENT 64 typedef struct memblock_s { int size; // including the header and possibly tiny fragments int tag; // a tag of 0 is a free block int id; // should be ZONEID int pad; // pad to 64 bit boundary struct memblock_s *next, *prev; } memblock_t; typedef struct { int size; // total bytes malloced, including header memblock_t blocklist; // start / end cap for linked list memblock_t *rover; } memzone_t; void Cache_FreeLow (int new_low_hunk); void Cache_FreeHigh (int new_high_hunk); /* ============================================================================== 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 The zone calls are pretty much only used for small strings and structures, all big things are allocated on the hunk. ============================================================================== */ static memzone_t *mainzone; /* ======================== Z_Free ======================== */ void Z_Free (void *ptr) { memblock_t *block, *other; if (!ptr) Sys_Error ("Z_Free: NULL pointer"); block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); if (block->id != ZONEID) Sys_Error ("Z_Free: freed a pointer without ZONEID"); if (block->tag == 0) Sys_Error ("Z_Free: freed a freed pointer"); block->tag = 0; // mark as free other = block->prev; if (!other->tag) { // 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) { // 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; } } static void *Z_TagMalloc (int size, int tag) { int extra; memblock_t *start, *rover, *newblock, *base; if (!tag) Sys_Error ("Z_TagMalloc: tried to use a 0 tag"); // // scan through the block list looking for the first free block // of sufficient size // size += sizeof(memblock_t); // account for size of block header size += 4; // space for memory trash tester size = (size + 7) & ~7; // align to 8-byte boundary base = rover = mainzone->rover; start = base->prev; do { if (rover == start) // scaned all the way around the list return NULL; if (rover->tag) base = rover = rover->next; else rover = rover->next; } while (base->tag || 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 = 0; // free block newblock->prev = base; newblock->id = ZONEID; newblock->next = base->next; newblock->next->prev = newblock; base->next = newblock; base->size = size; } base->tag = tag; // no longer a free block mainzone->rover = base->next; // next allocation will start looking here base->id = ZONEID; // marker for memory trash testing *(int *)((byte *)base + base->size - 4) = ZONEID; return (void *) ((byte *)base + sizeof(memblock_t)); } /* ======================== Z_CheckHeap ======================== */ static void Z_CheckHeap (void) { memblock_t *block; for (block = mainzone->blocklist.next ; ; block = block->next) { if (block->next == &mainzone->blocklist) break; // all blocks have been hit if ( (byte *)block + block->size != (byte *)block->next) Sys_Error ("Z_CheckHeap: block size does not touch the next block\n"); if ( block->next->prev != block) Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n"); if (!block->tag && !block->next->tag) Sys_Error ("Z_CheckHeap: two consecutive free blocks\n"); } } /* ======================== Z_Malloc ======================== */ void *Z_Malloc (int size) { void *buf; Z_CheckHeap (); // DEBUG buf = Z_TagMalloc (size, 1); if (!buf) Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size); Q_memset (buf, 0, size); return buf; } /* ======================== Z_Realloc ======================== */ void *Z_Realloc(void *ptr, int size) { int old_size; void *old_ptr; memblock_t *block; if (!ptr) return Z_Malloc (size); block = (memblock_t *) ((byte *) ptr - sizeof (memblock_t)); if (block->id != ZONEID) Sys_Error ("Z_Realloc: realloced a pointer without ZONEID"); if (block->tag == 0) Sys_Error ("Z_Realloc: realloced a freed pointer"); old_size = block->size; old_size -= (4 + (int)sizeof(memblock_t)); /* see Z_TagMalloc() */ old_ptr = ptr; Z_Free (ptr); ptr = Z_TagMalloc (size, 1); if (!ptr) Sys_Error ("Z_Realloc: failed on allocation of %i bytes", size); if (ptr != old_ptr) memmove (ptr, old_ptr, q_min(old_size, size)); if (old_size < size) memset ((byte *)ptr + old_size, 0, size - old_size); return ptr; } char *Z_Strdup (const char *s) { size_t sz = strlen(s) + 1; char *ptr = (char *) Z_Malloc (sz); memcpy (ptr, s, sz); return ptr; } /* ======================== Z_Print ======================== */ void Z_Print (memzone_t *zone) { memblock_t *block; Con_Printf ("zone size: %i location: %p\n",mainzone->size,mainzone); for (block = zone->blocklist.next ; ; block = block->next) { Con_Printf ("block:%p size:%7i tag:%3i\n", block, block->size, block->tag); if (block->next == &zone->blocklist) break; // all blocks have been hit if ( (byte *)block + block->size != (byte *)block->next) Con_Printf ("ERROR: block size does not touch the next block\n"); if ( block->next->prev != block) Con_Printf ("ERROR: next block doesn't have proper back link\n"); if (!block->tag && !block->next->tag) Con_Printf ("ERROR: two consecutive free blocks\n"); } } //============================================================================ #define HUNK_SENTINAL 0x1df001ed #define HUNKNAME_LEN 24 typedef struct { int sentinal; int size; // including sizeof(hunk_t), -1 = not allocated char name[HUNKNAME_LEN]; } hunk_t; byte *hunk_base; int hunk_size; int hunk_low_used; int hunk_high_used; qboolean hunk_tempactive; int hunk_tempmark; /* ============== Hunk_Check Run consistancy and sentinal trahing checks ============== */ void Hunk_Check (void) { hunk_t *h; for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; ) { if (h->sentinal != HUNK_SENTINAL) Sys_Error ("Hunk_Check: trahsed sentinal"); if (h->size < (int) sizeof(hunk_t) || h->size + (byte *)h - hunk_base > hunk_size) Sys_Error ("Hunk_Check: bad size"); h = (hunk_t *)((byte *)h+h->size); } } /* ============== Hunk_Print If "all" is specified, every single allocation is printed. Otherwise, allocations with the same name will be totaled up before printing. ============== */ void Hunk_Print (qboolean all) { hunk_t *h, *next, *endlow, *starthigh, *endhigh; int count, sum; int totalblocks; char name[HUNKNAME_LEN]; count = 0; sum = 0; totalblocks = 0; h = (hunk_t *)hunk_base; endlow = (hunk_t *)(hunk_base + hunk_low_used); starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); endhigh = (hunk_t *)(hunk_base + hunk_size); Con_Printf (" :%8i total hunk size\n", hunk_size); Con_Printf ("-------------------------\n"); while (1) { // // skip to the high hunk if done with low hunk // if ( h == endlow ) { Con_Printf ("-------------------------\n"); Con_Printf (" :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used); Con_Printf ("-------------------------\n"); h = starthigh; } // // if totally done, break // if ( h == endhigh ) break; // // run consistancy checks // if (h->sentinal != HUNK_SENTINAL) Sys_Error ("Hunk_Check: trahsed sentinal"); if (h->size < (int) sizeof(hunk_t) || h->size + (byte *)h - hunk_base > hunk_size) Sys_Error ("Hunk_Check: bad size"); next = (hunk_t *)((byte *)h+h->size); count++; totalblocks++; sum += h->size; // // print the single block // memcpy (name, h->name, HUNKNAME_LEN); if (all) Con_Printf ("%8p :%8i %8s\n",h, h->size, name); // // print the total // if (next == endlow || next == endhigh || strncmp (h->name, next->name, HUNKNAME_LEN - 1)) { if (!all) Con_Printf (" :%8i %8s (TOTAL)\n",sum, name); count = 0; sum = 0; } h = next; } Con_Printf ("-------------------------\n"); Con_Printf ("%8i total blocks\n", totalblocks); } /* =================== Hunk_Print_f -- johnfitz -- console command to call hunk_print =================== */ void Hunk_Print_f (void) { Hunk_Print (false); } /* =================== Hunk_AllocName =================== */ void *Hunk_AllocName (int size, const char *name) { hunk_t *h; #ifdef PARANOID Hunk_Check (); #endif if (size < 0) Sys_Error ("Hunk_Alloc: bad size: %i", size); size = sizeof(hunk_t) + ((size+15)&~15); if (hunk_size - hunk_low_used - hunk_high_used < size) Sys_Error ("Hunk_Alloc: failed on %i bytes",size); h = (hunk_t *)(hunk_base + hunk_low_used); hunk_low_used += size; Cache_FreeLow (hunk_low_used); memset (h, 0, size); h->size = size; h->sentinal = HUNK_SENTINAL; q_strlcpy (h->name, name, HUNKNAME_LEN); return (void *)(h+1); } /* =================== Hunk_Alloc =================== */ void *Hunk_Alloc (int size) { return Hunk_AllocName (size, "unknown"); } int Hunk_LowMark (void) { return hunk_low_used; } void Hunk_FreeToLowMark (int mark) { if (mark < 0 || mark > hunk_low_used) Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark); memset (hunk_base + mark, 0, hunk_low_used - mark); hunk_low_used = mark; } int Hunk_HighMark (void) { if (hunk_tempactive) { hunk_tempactive = false; Hunk_FreeToHighMark (hunk_tempmark); } return hunk_high_used; } void Hunk_FreeToHighMark (int mark) { if (hunk_tempactive) { hunk_tempactive = false; Hunk_FreeToHighMark (hunk_tempmark); } if (mark < 0 || mark > hunk_high_used) Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark); memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark); hunk_high_used = mark; } /* =================== Hunk_HighAllocName =================== */ void *Hunk_HighAllocName (int size, const char *name) { hunk_t *h; if (size < 0) Sys_Error ("Hunk_HighAllocName: bad size: %i", size); if (hunk_tempactive) { Hunk_FreeToHighMark (hunk_tempmark); hunk_tempactive = false; } #ifdef PARANOID Hunk_Check (); #endif size = sizeof(hunk_t) + ((size+15)&~15); if (hunk_size - hunk_low_used - hunk_high_used < size) { Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size); return NULL; } hunk_high_used += size; Cache_FreeHigh (hunk_high_used); h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); memset (h, 0, size); h->size = size; h->sentinal = HUNK_SENTINAL; q_strlcpy (h->name, name, HUNKNAME_LEN); return (void *)(h+1); } /* ================= Hunk_TempAlloc Return space from the top of the hunk ================= */ void *Hunk_TempAlloc (int size) { void *buf; size = (size+15)&~15; if (hunk_tempactive) { Hunk_FreeToHighMark (hunk_tempmark); hunk_tempactive = false; } hunk_tempmark = Hunk_HighMark (); buf = Hunk_HighAllocName (size, "temp"); hunk_tempactive = true; return buf; } char *Hunk_Strdup (const char *s, const char *name) { size_t sz = strlen(s) + 1; char *ptr = (char *) Hunk_AllocName (sz, name); memcpy (ptr, s, sz); return ptr; } /* =============================================================================== CACHE MEMORY =============================================================================== */ #define CACHENAME_LEN 32 typedef struct cache_system_s { int size; // including this header cache_user_t *user; char name[CACHENAME_LEN]; struct cache_system_s *prev, *next; struct cache_system_s *lru_prev, *lru_next; // for LRU flushing } cache_system_t; cache_system_t *Cache_TryAlloc (int size, qboolean nobottom); cache_system_t cache_head; /* =========== Cache_Move =========== */ void Cache_Move ( cache_system_t *c) { cache_system_t *new_cs; // we are clearing up space at the bottom, so only allocate it late new_cs = Cache_TryAlloc (c->size, true); if (new_cs) { // Con_Printf ("cache_move ok\n"); Q_memcpy ( new_cs+1, c+1, c->size - sizeof(cache_system_t) ); new_cs->user = c->user; Q_memcpy (new_cs->name, c->name, sizeof(new_cs->name)); Cache_Free (c->user, false); //johnfitz -- added second argument new_cs->user->data = (void *)(new_cs+1); } else { // Con_Printf ("cache_move failed\n"); Cache_Free (c->user, true); // tough luck... //johnfitz -- added second argument } } /* ============ Cache_FreeLow Throw things out until the hunk can be expanded to the given point ============ */ void Cache_FreeLow (int new_low_hunk) { cache_system_t *c; while (1) { c = cache_head.next; if (c == &cache_head) return; // nothing in cache at all if ((byte *)c >= hunk_base + new_low_hunk) return; // there is space to grow the hunk Cache_Move ( c ); // reclaim the space } } /* ============ Cache_FreeHigh Throw things out until the hunk can be expanded to the given point ============ */ void Cache_FreeHigh (int new_high_hunk) { cache_system_t *c, *prev; prev = NULL; while (1) { c = cache_head.prev; if (c == &cache_head) return; // nothing in cache at all if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk) return; // there is space to grow the hunk if (c == prev) Cache_Free (c->user, true); // didn't move out of the way //johnfitz -- added second argument else { Cache_Move (c); // try to move it prev = c; } } } void Cache_UnlinkLRU (cache_system_t *cs) { if (!cs->lru_next || !cs->lru_prev) Sys_Error ("Cache_UnlinkLRU: NULL link"); cs->lru_next->lru_prev = cs->lru_prev; cs->lru_prev->lru_next = cs->lru_next; cs->lru_prev = cs->lru_next = NULL; } void Cache_MakeLRU (cache_system_t *cs) { if (cs->lru_next || cs->lru_prev) Sys_Error ("Cache_MakeLRU: active link"); cache_head.lru_next->lru_prev = cs; cs->lru_next = cache_head.lru_next; cs->lru_prev = &cache_head; cache_head.lru_next = cs; } /* ============ Cache_TryAlloc Looks for a free block of memory between the high and low hunk marks Size should already include the header and padding ============ */ cache_system_t *Cache_TryAlloc (int size, qboolean nobottom) { cache_system_t *cs, *new_cs; // is the cache completely empty? if (!nobottom && cache_head.prev == &cache_head) { if (hunk_size - hunk_high_used - hunk_low_used < size) Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size); new_cs = (cache_system_t *) (hunk_base + hunk_low_used); memset (new_cs, 0, sizeof(*new_cs)); new_cs->size = size; cache_head.prev = cache_head.next = new_cs; new_cs->prev = new_cs->next = &cache_head; Cache_MakeLRU (new_cs); return new_cs; } // search from the bottom up for space new_cs = (cache_system_t *) (hunk_base + hunk_low_used); cs = cache_head.next; do { if (!nobottom || cs != cache_head.next) { if ( (byte *)cs - (byte *)new_cs >= size) { // found space memset (new_cs, 0, sizeof(*new_cs)); new_cs->size = size; new_cs->next = cs; new_cs->prev = cs->prev; cs->prev->next = new_cs; cs->prev = new_cs; Cache_MakeLRU (new_cs); return new_cs; } } // continue looking new_cs = (cache_system_t *)((byte *)cs + cs->size); cs = cs->next; } while (cs != &cache_head); // try to allocate one at the very end if ( hunk_base + hunk_size - hunk_high_used - (byte *)new_cs >= size) { memset (new_cs, 0, sizeof(*new_cs)); new_cs->size = size; new_cs->next = &cache_head; new_cs->prev = cache_head.prev; cache_head.prev->next = new_cs; cache_head.prev = new_cs; Cache_MakeLRU (new_cs); return new_cs; } return NULL; // couldn't allocate } /* ============ Cache_Flush Throw everything out, so new data will be demand cached ============ */ void Cache_Flush (void) { while (cache_head.next != &cache_head) Cache_Free ( cache_head.next->user, true); // reclaim the space //johnfitz -- added second argument } /* ============ Cache_Print ============ */ void Cache_Print (void) { cache_system_t *cd; for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next) { Con_Printf ("%8i : %s\n", cd->size, cd->name); } } /* ============ Cache_Report ============ */ void Cache_Report (void) { Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) ); } /* ============ Cache_Init ============ */ void Cache_Init (void) { cache_head.next = cache_head.prev = &cache_head; cache_head.lru_next = cache_head.lru_prev = &cache_head; Cmd_AddCommand ("flush", Cache_Flush); } /* ============== Cache_Free Frees the memory and removes it from the LRU list ============== */ void Cache_Free (cache_user_t *c, qboolean freetextures) //johnfitz -- added second argument { cache_system_t *cs; if (!c->data) Sys_Error ("Cache_Free: not allocated"); cs = ((cache_system_t *)c->data) - 1; cs->prev->next = cs->next; cs->next->prev = cs->prev; cs->next = cs->prev = NULL; c->data = NULL; Cache_UnlinkLRU (cs); //johnfitz -- if a model becomes uncached, free the gltextures. This only works //becuase the cache_user_t is the last component of the qmodel_t struct. Should //fail harmlessly if *c is actually part of an sfx_t struct. I FEEL DIRTY if (freetextures) TexMgr_FreeTexturesForOwner ((qmodel_t *)(c + 1) - 1); } /* ============== Cache_Check ============== */ void *Cache_Check (cache_user_t *c) { cache_system_t *cs; if (!c->data) return NULL; cs = ((cache_system_t *)c->data) - 1; // move to head of LRU Cache_UnlinkLRU (cs); Cache_MakeLRU (cs); return c->data; } /* ============== Cache_Alloc ============== */ void *Cache_Alloc (cache_user_t *c, int size, const char *name) { cache_system_t *cs; if (c->data) Sys_Error ("Cache_Alloc: allready allocated"); if (size <= 0) Sys_Error ("Cache_Alloc: size %i", size); size = (size + sizeof(cache_system_t) + 15) & ~15; // find memory for it while (1) { cs = Cache_TryAlloc (size, false); if (cs) { q_strlcpy (cs->name, name, CACHENAME_LEN); c->data = (void *)(cs+1); cs->user = c; break; } // free the least recently used cahedat if (cache_head.lru_prev == &cache_head) Sys_Error ("Cache_Alloc: out of memory"); // not enough memory at all Cache_Free (cache_head.lru_prev->user, true); //johnfitz -- added second argument } return Cache_Check (c); } //============================================================================ static void Memory_InitZone (memzone_t *zone, int size) { 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.tag = 1; // in use block zone->blocklist.id = 0; zone->blocklist.size = 0; zone->rover = block; block->prev = block->next = &zone->blocklist; block->tag = 0; // free block block->id = ZONEID; block->size = size - sizeof(memzone_t); } /* ======================== Memory_Init ======================== */ void Memory_Init (void *buf, int size) { int p; int zonesize = DYNAMIC_SIZE; hunk_base = (byte *) buf; hunk_size = size; hunk_low_used = 0; hunk_high_used = 0; Cache_Init (); p = COM_CheckParm ("-zone"); if (p) { if (p < com_argc-1) zonesize = Q_atoi (com_argv[p+1]) * 1024; else Sys_Error ("Memory_Init: you must specify a size in KB after -zone"); } mainzone = (memzone_t *) Hunk_AllocName (zonesize, "zone" ); Memory_InitZone (mainzone, zonesize); Cmd_AddCommand ("hunk_print", Hunk_Print_f); //johnfitz } ����������������������������������������������quakespasm-0.91.0/Quake/build_cross_osx-sdl2.sh�����������������������������������������������������0000755�0000000�0000000�00000002015�12406264714�020125� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh rm -f quakespasm.x86 quakespasm.x86_64 QuakeSpasm make clean OLDPATH=$PATH MAKE_CMD=make OSXBUILD=1 export OSXBUILD STRIP=/bin/true export STRIP # x86 PATH=/opt/cross_osx-x86.5/usr/bin:$OLDPATH CC=i686-apple-darwin9-gcc AS=i686-apple-darwin9-as AR=i686-apple-darwin9-ar RANLIB=i686-apple-darwin9-ranlib LIPO=i686-apple-darwin9-lipo export PATH CC AS AR RANLIB LIPO $MAKE_CMD MACH_TYPE=x86 USE_SDL2=1 -f Makefile.darwin $* || exit 1 i686-apple-darwin9-strip -S quakespasm || exit 1 mv quakespasm quakespasm.x86 || exit 1 $MAKE_CMD clean # x86_64 PATH=/opt/cross_osx-x86_64/usr/bin:$OLDPATH CC=x86_64-apple-darwin9-gcc AS=x86_64-apple-darwin9-as AR=x86_64-apple-darwin9-ar RANLIB=x86_64-apple-darwin9-ranlib LIPO=x86_64-apple-darwin9-lipo export PATH CC AS AR RANLIB LIPO $MAKE_CMD MACH_TYPE=x86_64 USE_SDL2=1 -f Makefile.darwin $* || exit 1 x86_64-apple-darwin9-strip -S quakespasm || exit 1 mv quakespasm quakespasm.x86_64 || exit 1 $MAKE_CMD clean $LIPO -create -o QuakeSpasm quakespasm.x86 quakespasm.x86_64 || exit 1 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_wave.c������������������������������������������������������������������0000644�0000000�0000000�00000013012�12220541170�015460� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * WAV streaming music support. Adapted from ioquake3 with changes. * * Copyright (C) 1999-2005 Id Software, Inc. * Copyright (C) 2005 Stuart Dalton <badcdev@gmail.com> * Copyright (C) 2010-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #include "quakedef.h" #if defined(USE_CODEC_WAVE) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_wave.h" /* ================= FGetLittleLong ================= */ static int FGetLittleLong (FILE *f) { int v; fread(&v, 1, sizeof(v), f); return LittleLong(v); } /* ================= FGetLittleShort ================= */ static short FGetLittleShort(FILE *f) { short v; fread(&v, 1, sizeof(v), f); return LittleShort(v); } /* ================= WAV_ReadChunkInfo ================= */ static int WAV_ReadChunkInfo(FILE *f, char *name) { int len, r; name[4] = 0; r = fread(name, 1, 4, f); if (r != 4) return -1; len = FGetLittleLong(f); if (len < 0) { Con_Printf("WAV: Negative chunk length\n"); return -1; } return len; } /* ================= WAV_FindRIFFChunk Returns the length of the data in the chunk, or -1 if not found ================= */ static int WAV_FindRIFFChunk(FILE *f, const char *chunk) { char name[5]; int len; while ((len = WAV_ReadChunkInfo(f, name)) >= 0) { /* If this is the right chunk, return */ if (!strncmp(name, chunk, 4)) return len; len = ((len + 1) & ~1); /* pad by 2 . */ /* Not the right chunk - skip it */ fseek(f, len, SEEK_CUR); } return -1; } /* ================= WAV_ReadRIFFHeader ================= */ static qboolean WAV_ReadRIFFHeader(const char *name, FILE *file, snd_info_t *info) { char dump[16]; int wav_format; int fmtlen = 0; if (fread(dump, 1, 12, file) < 12 || strncmp(dump, "RIFF", 4) != 0 || strncmp(&dump[8], "WAVE", 4) != 0) { Con_Printf("%s is missing RIFF/WAVE chunks\n", name); return false; } /* Scan for the format chunk */ if ((fmtlen = WAV_FindRIFFChunk(file, "fmt ")) < 0) { Con_Printf("%s is missing fmt chunk\n", name); return false; } /* Save the parameters */ wav_format = FGetLittleShort(file); if (wav_format != WAV_FORMAT_PCM) { Con_Printf("%s is not Microsoft PCM format\n", name); return false; } info->channels = FGetLittleShort(file); info->rate = FGetLittleLong(file); FGetLittleLong(file); FGetLittleShort(file); info->bits = FGetLittleShort(file); if (info->bits != 8 && info->bits != 16) { Con_Printf("%s is not 8 or 16 bit\n", name); return false; } info->width = info->bits / 8; info->dataofs = 0; /* Skip the rest of the format chunk if required */ if (fmtlen > 16) { fmtlen -= 16; fseek(file, fmtlen, SEEK_CUR); } /* Scan for the data chunk */ if ((info->size = WAV_FindRIFFChunk(file, "data")) < 0) { Con_Printf("%s is missing data chunk\n", name); return false; } if (info->channels != 1 && info->channels != 2) { Con_Printf("Unsupported number of channels %d in %s\n", info->channels, name); return false; } info->samples = (info->size / info->width) / info->channels; if (info->samples == 0) { Con_Printf("%s has zero samples\n", name); return false; } return true; } /* ================= S_WAV_CodecOpenStream ================= */ static qboolean S_WAV_CodecOpenStream(snd_stream_t *stream) { long start = stream->fh.start; /* Read the RIFF header */ /* The file reads are sequential, therefore no need * for the FS_*() functions: We will manipulate the * file by ourselves from now on. */ if (!WAV_ReadRIFFHeader(stream->name, stream->fh.file, &stream->info)) return false; stream->fh.start = ftell(stream->fh.file); /* reset to data position */ if (stream->fh.start - start + stream->info.size > stream->fh.length) { Con_Printf("%s data size mismatch\n", stream->name); return false; } return true; } /* ================= S_WAV_CodecReadStream ================= */ int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) { int remaining = stream->info.size - stream->fh.pos; int i, samples; if (remaining <= 0) return 0; if (bytes > remaining) bytes = remaining; stream->fh.pos += bytes; fread(buffer, 1, bytes, stream->fh.file); if (stream->info.width == 2) { samples = bytes / 2; for (i = 0; i < samples; i++) ((short *)buffer)[i] = LittleShort( ((short *)buffer)[i] ); } return bytes; } static void S_WAV_CodecCloseStream (snd_stream_t *stream) { S_CodecUtilClose(&stream); } static int S_WAV_CodecRewindStream (snd_stream_t *stream) { FS_rewind(&stream->fh); return 0; } static qboolean S_WAV_CodecInitialize (void) { return true; } static void S_WAV_CodecShutdown (void) { } snd_codec_t wav_codec = { CODECTYPE_WAVE, true, /* always available. */ "wav", S_WAV_CodecInitialize, S_WAV_CodecShutdown, S_WAV_CodecOpenStream, S_WAV_CodecReadStream, S_WAV_CodecRewindStream, S_WAV_CodecCloseStream, NULL }; #endif /* USE_CODEC_WAVE */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sv_user.c�������������������������������������������������������������������0000644�0000000�0000000�00000032254�12407762022�015361� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_user.c -- server code for moving users #include "quakedef.h" edict_t *sv_player; extern cvar_t sv_friction; cvar_t sv_edgefriction = {"edgefriction", "2", CVAR_NONE}; extern cvar_t sv_stopspeed; static vec3_t forward, right, up; vec3_t wishdir; float wishspeed; // world float *angles; float *origin; float *velocity; qboolean onground; usercmd_t cmd; cvar_t sv_idealpitchscale = {"sv_idealpitchscale","0.8",CVAR_NONE}; cvar_t sv_altnoclip = {"sv_altnoclip","1",CVAR_ARCHIVE}; //johnfitz /* =============== SV_SetIdealPitch =============== */ #define MAX_FORWARD 6 void SV_SetIdealPitch (void) { float angleval, sinval, cosval; trace_t tr; vec3_t top, bottom; float z[MAX_FORWARD]; int i, j; int step, dir, steps; if (!((int)sv_player->v.flags & FL_ONGROUND)) return; angleval = sv_player->v.angles[YAW] * M_PI*2 / 360; sinval = sin(angleval); cosval = cos(angleval); for (i=0 ; i<MAX_FORWARD ; i++) { top[0] = sv_player->v.origin[0] + cosval*(i+3)*12; top[1] = sv_player->v.origin[1] + sinval*(i+3)*12; top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2]; bottom[0] = top[0]; bottom[1] = top[1]; bottom[2] = top[2] - 160; tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player); if (tr.allsolid) return; // looking at a wall, leave ideal the way is was if (tr.fraction == 1) return; // near a dropoff z[i] = top[2] + tr.fraction*(bottom[2]-top[2]); } dir = 0; steps = 0; for (j=1 ; j<i ; j++) { step = z[j] - z[j-1]; if (step > -ON_EPSILON && step < ON_EPSILON) continue; if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) ) return; // mixed changes steps++; dir = step; } if (!dir) { sv_player->v.idealpitch = 0; return; } if (steps < 2) return; sv_player->v.idealpitch = -dir * sv_idealpitchscale.value; } /* ================== SV_UserFriction ================== */ void SV_UserFriction (void) { float *vel; float speed, newspeed, control; vec3_t start, stop; float friction; trace_t trace; vel = velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (!speed) return; // if the leading edge is over a dropoff, increase friction start[0] = stop[0] = origin[0] + vel[0]/speed*16; start[1] = stop[1] = origin[1] + vel[1]/speed*16; start[2] = origin[2] + sv_player->v.mins[2]; stop[2] = start[2] - 34; trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player); if (trace.fraction == 1.0) friction = sv_friction.value*sv_edgefriction.value; else friction = sv_friction.value; // apply friction control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed; newspeed = speed - host_frametime*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] = vel[0] * newspeed; vel[1] = vel[1] * newspeed; vel[2] = vel[2] * newspeed; } /* ============== SV_Accelerate ============== */ cvar_t sv_maxspeed = {"sv_maxspeed", "320", CVAR_NOTIFY|CVAR_SERVERINFO}; cvar_t sv_accelerate = {"sv_accelerate", "10", CVAR_NONE}; void SV_Accelerate (void) { int i; float addspeed, accelspeed, currentspeed; currentspeed = DotProduct (velocity, wishdir); addspeed = wishspeed - currentspeed; if (addspeed <= 0) return; accelspeed = sv_accelerate.value*host_frametime*wishspeed; if (accelspeed > addspeed) accelspeed = addspeed; for (i=0 ; i<3 ; i++) velocity[i] += accelspeed*wishdir[i]; } void SV_AirAccelerate (vec3_t wishveloc) { int i; float addspeed, wishspd, accelspeed, currentspeed; wishspd = VectorNormalize (wishveloc); if (wishspd > 30) wishspd = 30; currentspeed = DotProduct (velocity, wishveloc); addspeed = wishspd - currentspeed; if (addspeed <= 0) return; // accelspeed = sv_accelerate.value * host_frametime; accelspeed = sv_accelerate.value*wishspeed * host_frametime; if (accelspeed > addspeed) accelspeed = addspeed; for (i=0 ; i<3 ; i++) velocity[i] += accelspeed*wishveloc[i]; } void DropPunchAngle (void) { float len; len = VectorNormalize (sv_player->v.punchangle); len -= 10*host_frametime; if (len < 0) len = 0; VectorScale (sv_player->v.punchangle, len, sv_player->v.punchangle); } /* =================== SV_WaterMove =================== */ void SV_WaterMove (void) { int i; vec3_t wishvel; float speed, newspeed, addspeed, accelspeed; //float wishspeed; // // user intentions // AngleVectors (sv_player->v.v_angle, forward, right, up); for (i=0 ; i<3 ; i++) wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove; if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove) wishvel[2] -= 60; // drift towards bottom else wishvel[2] += cmd.upmove; wishspeed = VectorLength(wishvel); if (wishspeed > sv_maxspeed.value) { VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel); wishspeed = sv_maxspeed.value; } wishspeed *= 0.7; // // water friction // speed = VectorLength (velocity); if (speed) { newspeed = speed - host_frametime * speed * sv_friction.value; if (newspeed < 0) newspeed = 0; VectorScale (velocity, newspeed/speed, velocity); } else newspeed = 0; // // water acceleration // if (!wishspeed) return; addspeed = wishspeed - newspeed; if (addspeed <= 0) return; VectorNormalize (wishvel); accelspeed = sv_accelerate.value * wishspeed * host_frametime; if (accelspeed > addspeed) accelspeed = addspeed; for (i=0 ; i<3 ; i++) velocity[i] += accelspeed * wishvel[i]; } void SV_WaterJump (void) { if (sv.time > sv_player->v.teleport_time || !sv_player->v.waterlevel) { sv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP; sv_player->v.teleport_time = 0; } sv_player->v.velocity[0] = sv_player->v.movedir[0]; sv_player->v.velocity[1] = sv_player->v.movedir[1]; } /* =================== SV_NoclipMove -- johnfitz new, alternate noclip. old noclip is still handled in SV_AirMove =================== */ void SV_NoclipMove (void) { AngleVectors (sv_player->v.v_angle, forward, right, up); velocity[0] = forward[0]*cmd.forwardmove + right[0]*cmd.sidemove; velocity[1] = forward[1]*cmd.forwardmove + right[1]*cmd.sidemove; velocity[2] = forward[2]*cmd.forwardmove + right[2]*cmd.sidemove; velocity[2] += cmd.upmove*2; //doubled to match running speed if (VectorLength (velocity) > sv_maxspeed.value) { VectorNormalize (velocity); VectorScale (velocity, sv_maxspeed.value, velocity); } } /* =================== SV_AirMove =================== */ void SV_AirMove (void) { int i; vec3_t wishvel; float fmove, smove; AngleVectors (sv_player->v.angles, forward, right, up); fmove = cmd.forwardmove; smove = cmd.sidemove; // hack to not let you back into teleporter if (sv.time < sv_player->v.teleport_time && fmove < 0) fmove = 0; for (i=0 ; i<3 ; i++) wishvel[i] = forward[i]*fmove + right[i]*smove; if ( (int)sv_player->v.movetype != MOVETYPE_WALK) wishvel[2] = cmd.upmove; else wishvel[2] = 0; VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); if (wishspeed > sv_maxspeed.value) { VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel); wishspeed = sv_maxspeed.value; } if ( sv_player->v.movetype == MOVETYPE_NOCLIP) { // noclip VectorCopy (wishvel, velocity); } else if ( onground ) { SV_UserFriction (); SV_Accelerate (); } else { // not on ground, so little effect on velocity SV_AirAccelerate (wishvel); } } /* =================== SV_ClientThink the move fields specify an intended velocity in pix/sec the angle fields specify an exact angular motion in degrees =================== */ void SV_ClientThink (void) { vec3_t v_angle; if (sv_player->v.movetype == MOVETYPE_NONE) return; onground = (int)sv_player->v.flags & FL_ONGROUND; origin = sv_player->v.origin; velocity = sv_player->v.velocity; DropPunchAngle (); // // if dead, behave differently // if (sv_player->v.health <= 0) return; // // angles // show 1/3 the pitch angle and all the roll angle cmd = host_client->cmd; angles = sv_player->v.angles; VectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle); angles[ROLL] = V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4; if (!sv_player->v.fixangle) { angles[PITCH] = -v_angle[PITCH]/3; angles[YAW] = v_angle[YAW]; } if ( (int)sv_player->v.flags & FL_WATERJUMP ) { SV_WaterJump (); return; } // // walk // //johnfitz -- alternate noclip if (sv_player->v.movetype == MOVETYPE_NOCLIP && sv_altnoclip.value) SV_NoclipMove (); else if (sv_player->v.waterlevel >= 2 && sv_player->v.movetype != MOVETYPE_NOCLIP) SV_WaterMove (); else SV_AirMove (); //johnfitz } /* =================== SV_ReadClientMove =================== */ void SV_ReadClientMove (usercmd_t *move) { int i; vec3_t angle; int bits; // read ping time host_client->ping_times[host_client->num_pings%NUM_PING_TIMES] = sv.time - MSG_ReadFloat (); host_client->num_pings++; // read current angles for (i=0 ; i<3 ; i++) //johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE if (sv.protocol == PROTOCOL_NETQUAKE) angle[i] = MSG_ReadAngle (); else angle[i] = MSG_ReadAngle16 (); //johnfitz VectorCopy (angle, host_client->edict->v.v_angle); // read movement move->forwardmove = MSG_ReadShort (); move->sidemove = MSG_ReadShort (); move->upmove = MSG_ReadShort (); // read buttons bits = MSG_ReadByte (); host_client->edict->v.button0 = bits & 1; host_client->edict->v.button2 = (bits & 2)>>1; i = MSG_ReadByte (); if (i) host_client->edict->v.impulse = i; } /* =================== SV_ReadClientMessage Returns false if the client should be killed =================== */ qboolean SV_ReadClientMessage (void) { int ret; int ccmd; const char *s; do { nextmsg: ret = NET_GetMessage (host_client->netconnection); if (ret == -1) { Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); return false; } if (!ret) return true; MSG_BeginReading (); while (1) { if (!host_client->active) return false; // a command caused an error if (msg_badread) { Sys_Printf ("SV_ReadClientMessage: badread\n"); return false; } ccmd = MSG_ReadChar (); switch (ccmd) { case -1: goto nextmsg; // end of message default: Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); return false; case clc_nop: // Sys_Printf ("clc_nop\n"); break; case clc_stringcmd: s = MSG_ReadString (); ret = 0; if (q_strncasecmp(s, "status", 6) == 0) ret = 1; else if (q_strncasecmp(s, "god", 3) == 0) ret = 1; else if (q_strncasecmp(s, "notarget", 8) == 0) ret = 1; else if (q_strncasecmp(s, "fly", 3) == 0) ret = 1; else if (q_strncasecmp(s, "name", 4) == 0) ret = 1; else if (q_strncasecmp(s, "noclip", 6) == 0) ret = 1; else if (q_strncasecmp(s, "say", 3) == 0) ret = 1; else if (q_strncasecmp(s, "say_team", 8) == 0) ret = 1; else if (q_strncasecmp(s, "tell", 4) == 0) ret = 1; else if (q_strncasecmp(s, "color", 5) == 0) ret = 1; else if (q_strncasecmp(s, "kill", 4) == 0) ret = 1; else if (q_strncasecmp(s, "pause", 5) == 0) ret = 1; else if (q_strncasecmp(s, "spawn", 5) == 0) ret = 1; else if (q_strncasecmp(s, "begin", 5) == 0) ret = 1; else if (q_strncasecmp(s, "prespawn", 8) == 0) ret = 1; else if (q_strncasecmp(s, "kick", 4) == 0) ret = 1; else if (q_strncasecmp(s, "ping", 4) == 0) ret = 1; else if (q_strncasecmp(s, "give", 4) == 0) ret = 1; else if (q_strncasecmp(s, "ban", 3) == 0) ret = 1; if (ret == 1) Cmd_ExecuteString (s, src_client); else Con_DPrintf("%s tried to %s\n", host_client->name, s); break; case clc_disconnect: // Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); return false; case clc_move: SV_ReadClientMove (&host_client->cmd); break; } } } while (ret == 1); return true; } /* ================== SV_RunClients ================== */ void SV_RunClients (void) { int i; for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) { if (!host_client->active) continue; sv_player = host_client->edict; if (!SV_ReadClientMessage ()) { SV_DropClient (false); // client misbehaved... continue; } if (!host_client->spawned) { // clear client movement until a new packet is received memset (&host_client->cmd, 0, sizeof(host_client->cmd)); continue; } // always pause in single player if in console or menus if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) SV_ClientThink (); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/bspfile.h�������������������������������������������������������������������0000644�0000000�0000000�00000021651�12407762022�015323� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __BSPFILE_H #define __BSPFILE_H // upper design bounds #define MAX_MAP_HULLS 4 #define MAX_MAP_MODELS 256 #define MAX_MAP_BRUSHES 4096 #define MAX_MAP_ENTITIES 1024 #define MAX_MAP_ENTSTRING 65536 #define MAX_MAP_PLANES 32767 #define MAX_MAP_NODES 32767 // because negative shorts are contents #define MAX_MAP_CLIPNODES 32767 #define MAX_MAP_LEAFS 65535 //johnfitz -- was 8192 #define MAX_MAP_VERTS 65535 #define MAX_MAP_FACES 65535 #define MAX_MAP_MARKSURFACES 65535 #define MAX_MAP_TEXINFO 4096 #define MAX_MAP_EDGES 256000 #define MAX_MAP_SURFEDGES 512000 #define MAX_MAP_TEXTURES 512 #define MAX_MAP_MIPTEX 0x200000 #define MAX_MAP_LIGHTING 0x100000 #define MAX_MAP_VISIBILITY 0x100000 #define MAX_MAP_PORTALS 65536 // key / value pair sizes #define MAX_KEY 32 #define MAX_VALUE 1024 //============================================================================= #define BSPVERSION 29 /* RMQ support (2PSB). 32bits instead of shorts for all but bbox sizes (which * still use shorts) */ #define BSP2VERSION_2PSB (('B' << 24) | ('S' << 16) | ('P' << 8) | '2') /* BSP2 support. 32bits instead of shorts for everything (bboxes use floats) */ #define BSP2VERSION_BSP2 (('B' << 0) | ('S' << 8) | ('P' << 16) | ('2'<<24)) #define TOOLVERSION 2 typedef struct { int fileofs, filelen; } lump_t; #define LUMP_ENTITIES 0 #define LUMP_PLANES 1 #define LUMP_TEXTURES 2 #define LUMP_VERTEXES 3 #define LUMP_VISIBILITY 4 #define LUMP_NODES 5 #define LUMP_TEXINFO 6 #define LUMP_FACES 7 #define LUMP_LIGHTING 8 #define LUMP_CLIPNODES 9 #define LUMP_LEAFS 10 #define LUMP_MARKSURFACES 11 #define LUMP_EDGES 12 #define LUMP_SURFEDGES 13 #define LUMP_MODELS 14 #define HEADER_LUMPS 15 typedef struct { float mins[3], maxs[3]; float origin[3]; int headnode[MAX_MAP_HULLS]; int visleafs; // not including the solid leaf 0 int firstface, numfaces; } dmodel_t; typedef struct { int version; lump_t lumps[HEADER_LUMPS]; } dheader_t; typedef struct { int nummiptex; int dataofs[4]; // [nummiptex] } dmiptexlump_t; #define MIPLEVELS 4 typedef struct miptex_s { char name[16]; unsigned width, height; unsigned offsets[MIPLEVELS]; // four mip maps stored } miptex_t; typedef struct { float point[3]; } dvertex_t; // 0-2 are axial planes #define PLANE_X 0 #define PLANE_Y 1 #define PLANE_Z 2 // 3-5 are non-axial planes snapped to the nearest #define PLANE_ANYX 3 #define PLANE_ANYY 4 #define PLANE_ANYZ 5 typedef struct { float normal[3]; float dist; int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate } dplane_t; #define CONTENTS_EMPTY -1 #define CONTENTS_SOLID -2 #define CONTENTS_WATER -3 #define CONTENTS_SLIME -4 #define CONTENTS_LAVA -5 #define CONTENTS_SKY -6 #define CONTENTS_ORIGIN -7 // removed at csg time #define CONTENTS_CLIP -8 // changed to contents_solid #define CONTENTS_CURRENT_0 -9 #define CONTENTS_CURRENT_90 -10 #define CONTENTS_CURRENT_180 -11 #define CONTENTS_CURRENT_270 -12 #define CONTENTS_CURRENT_UP -13 #define CONTENTS_CURRENT_DOWN -14 // !!! if this is changed, it must be changed in asm_i386.h too !!! typedef struct { int planenum; short children[2]; // negative numbers are -(leafs+1), not nodes short mins[3]; // for sphere culling short maxs[3]; unsigned short firstface; unsigned short numfaces; // counting both sides } dsnode_t; typedef struct { int planenum; int children[2]; // negative numbers are -(leafs+1), not nodes short mins[3]; // for sphere culling short maxs[3]; unsigned int firstface; unsigned int numfaces; // counting both sides } dl1node_t; typedef struct { int planenum; int children[2]; // negative numbers are -(leafs+1), not nodes float mins[3]; // for sphere culling float maxs[3]; unsigned int firstface; unsigned int numfaces; // counting both sides } dl2node_t; typedef struct { int planenum; short children[2]; // negative numbers are contents } dsclipnode_t; typedef struct { int planenum; int children[2]; // negative numbers are contents } dlclipnode_t; typedef struct texinfo_s { float vecs[2][4]; // [s/t][xyz offset] int miptex; int flags; } texinfo_t; #define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision #define TEX_MISSING 2 // johnfitz -- this texinfo does not have a texture // note that edge 0 is never used, because negative edge nums are used for // counterclockwise use of the edge in a face typedef struct { unsigned short v[2]; // vertex numbers } dsedge_t; typedef struct { unsigned int v[2]; // vertex numbers } dledge_t; #define MAXLIGHTMAPS 4 typedef struct { short planenum; short side; int firstedge; // we must support > 64k edges short numedges; short texinfo; // lighting info byte styles[MAXLIGHTMAPS]; int lightofs; // start of [numstyles*surfsize] samples } dsface_t; typedef struct { int planenum; int side; int firstedge; // we must support > 64k edges int numedges; int texinfo; // lighting info byte styles[MAXLIGHTMAPS]; int lightofs; // start of [numstyles*surfsize] samples } dlface_t; #define AMBIENT_WATER 0 #define AMBIENT_SKY 1 #define AMBIENT_SLIME 2 #define AMBIENT_LAVA 3 #define NUM_AMBIENTS 4 // automatic ambient sounds // leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas // all other leafs need visibility info typedef struct { int contents; int visofs; // -1 = no visibility info short mins[3]; // for frustum culling short maxs[3]; unsigned short firstmarksurface; unsigned short nummarksurfaces; byte ambient_level[NUM_AMBIENTS]; } dsleaf_t; typedef struct { int contents; int visofs; // -1 = no visibility info short mins[3]; // for frustum culling short maxs[3]; unsigned int firstmarksurface; unsigned int nummarksurfaces; byte ambient_level[NUM_AMBIENTS]; } dl1leaf_t; typedef struct { int contents; int visofs; // -1 = no visibility info float mins[3]; // for frustum culling float maxs[3]; unsigned int firstmarksurface; unsigned int nummarksurfaces; byte ambient_level[NUM_AMBIENTS]; } dl2leaf_t; //============================================================================ #ifndef QUAKE_GAME #define ANGLE_UP -1 #define ANGLE_DOWN -2 // the utilities get to be lazy and just use large static arrays extern int nummodels; extern dmodel_t dmodels[MAX_MAP_MODELS]; extern int visdatasize; extern byte dvisdata[MAX_MAP_VISIBILITY]; extern int lightdatasize; extern byte dlightdata[MAX_MAP_LIGHTING]; extern int texdatasize; extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t) extern int entdatasize; extern char dentdata[MAX_MAP_ENTSTRING]; extern int numleafs; extern dleaf_t dleafs[MAX_MAP_LEAFS]; extern int numplanes; extern dplane_t dplanes[MAX_MAP_PLANES]; extern int numvertexes; extern dvertex_t dvertexes[MAX_MAP_VERTS]; extern int numnodes; extern dnode_t dnodes[MAX_MAP_NODES]; extern int numtexinfo; extern texinfo_t texinfo[MAX_MAP_TEXINFO]; extern int numfaces; extern dface_t dfaces[MAX_MAP_FACES]; extern int numclipnodes; extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES]; extern int numedges; extern dedge_t dedges[MAX_MAP_EDGES]; extern int nummarksurfaces; extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES]; extern int numsurfedges; extern int dsurfedges[MAX_MAP_SURFEDGES]; void DecompressVis (byte *in, byte *decompressed); int CompressVis (byte *vis, byte *dest); void LoadBSPFile (char *filename); void WriteBSPFile (char *filename); void PrintBSPFileSizes (void); //=============== typedef struct epair_s { struct epair_s *next; char *key; char *value; } epair_t; typedef struct { vec3_t origin; int firstbrush; int numbrushes; epair_t *epairs; } entity_t; extern int num_entities; extern entity_t entities[MAX_MAP_ENTITIES]; void ParseEntities (void); void UnparseEntities (void); void SetKeyValue (entity_t *ent, char *key, char *value); char *ValueForKey (entity_t *ent, char *key); // will return "" if not present vec_t FloatForKey (entity_t *ent, char *key); void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); epair_t *ParseEpair (void); #endif /* QUAKE_GAME */ #endif /* __BSPFILE_H */ ���������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_rmain.c������������������������������������������������������������������0000644�0000000�0000000�00000064220�12633216330�015456� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // r_main.c #include "quakedef.h" qboolean r_cache_thrash; // compatability vec3_t modelorg, r_entorigin; entity_t *currententity; int r_visframecount; // bumped when going to a new PVS int r_framecount; // used for dlight push checking mplane_t frustum[4]; //johnfitz -- rendering statistics int rs_brushpolys, rs_aliaspolys, rs_skypolys, rs_particles, rs_fogpolys; int rs_dynamiclightmaps, rs_brushpasses, rs_aliaspasses, rs_skypasses; float rs_megatexels; // // view origin // vec3_t vup; vec3_t vpn; vec3_t vright; vec3_t r_origin; float r_fovx, r_fovy; //johnfitz -- rendering fov may be different becuase of r_waterwarp and r_stereo // // screen size info // refdef_t r_refdef; mleaf_t *r_viewleaf, *r_oldviewleaf; int d_lightstylevalue[256]; // 8.8 fraction of base light value cvar_t r_norefresh = {"r_norefresh","0",CVAR_NONE}; cvar_t r_drawentities = {"r_drawentities","1",CVAR_NONE}; cvar_t r_drawviewmodel = {"r_drawviewmodel","1",CVAR_NONE}; cvar_t r_speeds = {"r_speeds","0",CVAR_NONE}; cvar_t r_pos = {"r_pos","0",CVAR_NONE}; cvar_t r_fullbright = {"r_fullbright","0",CVAR_NONE}; cvar_t r_lightmap = {"r_lightmap","0",CVAR_NONE}; cvar_t r_shadows = {"r_shadows","0",CVAR_ARCHIVE}; cvar_t r_wateralpha = {"r_wateralpha","1",CVAR_ARCHIVE}; cvar_t r_dynamic = {"r_dynamic","1",CVAR_ARCHIVE}; cvar_t r_novis = {"r_novis","0",CVAR_ARCHIVE}; cvar_t gl_finish = {"gl_finish","0",CVAR_NONE}; cvar_t gl_clear = {"gl_clear","0",CVAR_NONE}; cvar_t gl_cull = {"gl_cull","1",CVAR_NONE}; cvar_t gl_smoothmodels = {"gl_smoothmodels","1",CVAR_NONE}; cvar_t gl_affinemodels = {"gl_affinemodels","0",CVAR_NONE}; cvar_t gl_polyblend = {"gl_polyblend","1",CVAR_NONE}; cvar_t gl_flashblend = {"gl_flashblend","0",CVAR_ARCHIVE}; cvar_t gl_playermip = {"gl_playermip","0",CVAR_NONE}; cvar_t gl_nocolors = {"gl_nocolors","0",CVAR_NONE}; //johnfitz -- new cvars cvar_t r_stereo = {"r_stereo","0",CVAR_NONE}; cvar_t r_stereodepth = {"r_stereodepth","128",CVAR_NONE}; cvar_t r_clearcolor = {"r_clearcolor","2",CVAR_ARCHIVE}; cvar_t r_drawflat = {"r_drawflat","0",CVAR_NONE}; cvar_t r_flatlightstyles = {"r_flatlightstyles", "0", CVAR_NONE}; cvar_t gl_fullbrights = {"gl_fullbrights", "1", CVAR_ARCHIVE}; cvar_t gl_farclip = {"gl_farclip", "16384", CVAR_ARCHIVE}; cvar_t gl_overbright = {"gl_overbright", "1", CVAR_ARCHIVE}; cvar_t gl_overbright_models = {"gl_overbright_models", "1", CVAR_ARCHIVE}; cvar_t r_oldskyleaf = {"r_oldskyleaf", "0", CVAR_NONE}; cvar_t r_drawworld = {"r_drawworld", "1", CVAR_NONE}; cvar_t r_showtris = {"r_showtris", "0", CVAR_NONE}; cvar_t r_showbboxes = {"r_showbboxes", "0", CVAR_NONE}; cvar_t r_lerpmodels = {"r_lerpmodels", "1", CVAR_NONE}; cvar_t r_lerpmove = {"r_lerpmove", "1", CVAR_NONE}; cvar_t r_nolerp_list = {"r_nolerp_list", "progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", CVAR_NONE}; cvar_t r_noshadow_list = {"r_noshadow_list", "progs/flame2.mdl,progs/flame.mdl,progs/bolt1.mdl,progs/bolt2.mdl,progs/bolt3.mdl,progs/laser.mdl", CVAR_NONE}; extern cvar_t r_vfog; //johnfitz cvar_t gl_zfix = {"gl_zfix", "0", CVAR_NONE}; // QuakeSpasm z-fighting fix cvar_t r_lavaalpha = {"r_lavaalpha","0",CVAR_NONE}; cvar_t r_telealpha = {"r_telealpha","0",CVAR_NONE}; cvar_t r_slimealpha = {"r_slimealpha","0",CVAR_NONE}; float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha; qboolean r_drawflat_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe, r_drawworld_cheatsafe; //johnfitz //============================================================================== // // GLSL GAMMA CORRECTION // //============================================================================== static GLuint r_gamma_texture; static GLuint r_gamma_program; static int r_gamma_texture_width, r_gamma_texture_height; // uniforms used in gamma shader static GLuint gammaLoc; static GLuint textureLoc; /* ============= GLSLGamma_DeleteTexture ============= */ void GLSLGamma_DeleteTexture (void) { glDeleteTextures (1, &r_gamma_texture); r_gamma_texture = 0; r_gamma_program = 0; // deleted in R_DeleteShaders } /* ============= GLSLGamma_CreateShaders ============= */ static void GLSLGamma_CreateShaders (void) { const GLchar *vertSource = \ "#version 110\n" "\n" "void main(void) {\n" " gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);\n" " gl_TexCoord[0] = gl_MultiTexCoord0;\n" "}\n"; const GLchar *fragSource = \ "#version 110\n" "\n" "uniform sampler2D GammaTexture;\n" "uniform float GammaValue;\n" "\n" "void main(void) {\n" " vec4 frag = texture2D(GammaTexture, gl_TexCoord[0].xy);\n" " gl_FragColor = vec4(pow(frag.rgb, vec3(GammaValue)), 1.0);\n" "}\n"; if (!gl_glsl_gamma_able) return; r_gamma_program = GL_CreateProgram (vertSource, fragSource, 0, NULL); // get uniform locations gammaLoc = GL_GetUniformLocation (&r_gamma_program, "GammaValue"); textureLoc = GL_GetUniformLocation (&r_gamma_program, "GammaTexture"); } /* ============= GLSLGamma_GammaCorrect ============= */ void GLSLGamma_GammaCorrect (void) { float smax, tmax; if (!gl_glsl_gamma_able) return; if (vid_gamma.value == 1) return; // create render-to-texture texture if needed if (!r_gamma_texture) { glGenTextures (1, &r_gamma_texture); glBindTexture (GL_TEXTURE_2D, r_gamma_texture); r_gamma_texture_width = glwidth; r_gamma_texture_height = glheight; if (!gl_texture_NPOT) { r_gamma_texture_width = TexMgr_Pad(r_gamma_texture_width); r_gamma_texture_height = TexMgr_Pad(r_gamma_texture_height); } glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, r_gamma_texture_width, r_gamma_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } // create shader if needed if (!r_gamma_program) { GLSLGamma_CreateShaders (); if (!r_gamma_program) { Sys_Error("GLSLGamma_CreateShaders failed"); } } // copy the framebuffer to the texture GL_DisableMultitexture(); glBindTexture (GL_TEXTURE_2D, r_gamma_texture); glCopyTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, glx, gly, glwidth, glheight); // draw the texture back to the framebuffer with a fragment shader GL_UseProgramFunc (r_gamma_program); GL_Uniform1fFunc (gammaLoc, vid_gamma.value); GL_Uniform1iFunc (textureLoc, 0); // use texture unit 0 glDisable (GL_ALPHA_TEST); glDisable (GL_DEPTH_TEST); glViewport (glx, gly, glwidth, glheight); smax = glwidth/(float)r_gamma_texture_width; tmax = glheight/(float)r_gamma_texture_height; glBegin (GL_QUADS); glTexCoord2f (0, 0); glVertex2f (-1, -1); glTexCoord2f (smax, 0); glVertex2f (1, -1); glTexCoord2f (smax, tmax); glVertex2f (1, 1); glTexCoord2f (0, tmax); glVertex2f (-1, 1); glEnd (); GL_UseProgramFunc (0); // clear cached binding GL_ClearBindings (); } /* ================= R_CullBox -- johnfitz -- replaced with new function from lordhavoc Returns true if the box is completely outside the frustum ================= */ qboolean R_CullBox (vec3_t emins, vec3_t emaxs) { int i; mplane_t *p; for (i = 0;i < 4;i++) { p = frustum + i; switch(p->signbits) { default: case 0: if (p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2] < p->dist) return true; break; case 1: if (p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2] < p->dist) return true; break; case 2: if (p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2] < p->dist) return true; break; case 3: if (p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2] < p->dist) return true; break; case 4: if (p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2] < p->dist) return true; break; case 5: if (p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2] < p->dist) return true; break; case 6: if (p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2] < p->dist) return true; break; case 7: if (p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2] < p->dist) return true; break; } } return false; } /* =============== R_CullModelForEntity -- johnfitz -- uses correct bounds based on rotation =============== */ qboolean R_CullModelForEntity (entity_t *e) { vec3_t mins, maxs; if (e->angles[0] || e->angles[2]) //pitch or roll { VectorAdd (e->origin, e->model->rmins, mins); VectorAdd (e->origin, e->model->rmaxs, maxs); } else if (e->angles[1]) //yaw { VectorAdd (e->origin, e->model->ymins, mins); VectorAdd (e->origin, e->model->ymaxs, maxs); } else //no rotation { VectorAdd (e->origin, e->model->mins, mins); VectorAdd (e->origin, e->model->maxs, maxs); } return R_CullBox (mins, maxs); } /* =============== R_RotateForEntity -- johnfitz -- modified to take origin and angles instead of pointer to entity =============== */ void R_RotateForEntity (vec3_t origin, vec3_t angles) { glTranslatef (origin[0], origin[1], origin[2]); glRotatef (angles[1], 0, 0, 1); glRotatef (-angles[0], 0, 1, 0); glRotatef (angles[2], 1, 0, 0); } /* ============= GL_PolygonOffset -- johnfitz negative offset moves polygon closer to camera ============= */ void GL_PolygonOffset (int offset) { if (offset > 0) { glEnable (GL_POLYGON_OFFSET_FILL); glEnable (GL_POLYGON_OFFSET_LINE); glPolygonOffset(1, offset); } else if (offset < 0) { glEnable (GL_POLYGON_OFFSET_FILL); glEnable (GL_POLYGON_OFFSET_LINE); glPolygonOffset(-1, offset); } else { glDisable (GL_POLYGON_OFFSET_FILL); glDisable (GL_POLYGON_OFFSET_LINE); } } //============================================================================== // // SETUP FRAME // //============================================================================== int SignbitsForPlane (mplane_t *out) { int bits, j; // for fast box on planeside test bits = 0; for (j=0 ; j<3 ; j++) { if (out->normal[j] < 0) bits |= 1<<j; } return bits; } /* =============== TurnVector -- johnfitz turn forward towards side on the plane defined by forward and side if angle = 90, the result will be equal to side assumes side and forward are perpendicular, and normalized to turn away from side, use a negative angle =============== */ #define DEG2RAD( a ) ( (a) * M_PI_DIV_180 ) void TurnVector (vec3_t out, const vec3_t forward, const vec3_t side, float angle) { float scale_forward, scale_side; scale_forward = cos( DEG2RAD( angle ) ); scale_side = sin( DEG2RAD( angle ) ); out[0] = scale_forward*forward[0] + scale_side*side[0]; out[1] = scale_forward*forward[1] + scale_side*side[1]; out[2] = scale_forward*forward[2] + scale_side*side[2]; } /* =============== R_SetFrustum -- johnfitz -- rewritten =============== */ void R_SetFrustum (float fovx, float fovy) { int i; if (r_stereo.value) fovx += 10; //silly hack so that polygons don't drop out becuase of stereo skew TurnVector(frustum[0].normal, vpn, vright, fovx/2 - 90); //left plane TurnVector(frustum[1].normal, vpn, vright, 90 - fovx/2); //right plane TurnVector(frustum[2].normal, vpn, vup, 90 - fovy/2); //bottom plane TurnVector(frustum[3].normal, vpn, vup, fovy/2 - 90); //top plane for (i=0 ; i<4 ; i++) { frustum[i].type = PLANE_ANYZ; frustum[i].dist = DotProduct (r_origin, frustum[i].normal); //FIXME: shouldn't this always be zero? frustum[i].signbits = SignbitsForPlane (&frustum[i]); } } /* ============= GL_SetFrustum -- johnfitz -- written to replace MYgluPerspective ============= */ #define NEARCLIP 4 float frustum_skew = 0.0; //used by r_stereo void GL_SetFrustum(float fovx, float fovy) { float xmax, ymax; xmax = NEARCLIP * tan( fovx * M_PI / 360.0 ); ymax = NEARCLIP * tan( fovy * M_PI / 360.0 ); glFrustum(-xmax + frustum_skew, xmax + frustum_skew, -ymax, ymax, NEARCLIP, gl_farclip.value); } /* ============= R_SetupGL ============= */ void R_SetupGL (void) { //johnfitz -- rewrote this section glMatrixMode(GL_PROJECTION); glLoadIdentity (); glViewport (glx + r_refdef.vrect.x, gly + glheight - r_refdef.vrect.y - r_refdef.vrect.height, r_refdef.vrect.width, r_refdef.vrect.height); //johnfitz GL_SetFrustum (r_fovx, r_fovy); //johnfitz -- use r_fov* vars // glCullFace(GL_BACK); //johnfitz -- glquake used CCW with backwards culling -- let's do it right glMatrixMode(GL_MODELVIEW); glLoadIdentity (); glRotatef (-90, 1, 0, 0); // put Z going up glRotatef (90, 0, 0, 1); // put Z going up glRotatef (-r_refdef.viewangles[2], 1, 0, 0); glRotatef (-r_refdef.viewangles[0], 0, 1, 0); glRotatef (-r_refdef.viewangles[1], 0, 0, 1); glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); // // set drawing parms // if (gl_cull.value) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); glEnable(GL_DEPTH_TEST); } /* ============= R_Clear -- johnfitz -- rewritten and gutted ============= */ void R_Clear (void) { unsigned int clearbits; clearbits = GL_DEPTH_BUFFER_BIT; // from mh -- if we get a stencil buffer, we should clear it, even though we don't use it if (gl_stencilbits) clearbits |= GL_STENCIL_BUFFER_BIT; if (gl_clear.value) clearbits |= GL_COLOR_BUFFER_BIT; glClear (clearbits); } /* =============== R_SetupScene -- johnfitz -- this is the stuff that needs to be done once per eye in stereo mode =============== */ void R_SetupScene (void) { R_PushDlights (); R_AnimateLight (); r_framecount++; R_SetupGL (); } /* =============== R_SetupView -- johnfitz -- this is the stuff that needs to be done once per frame, even in stereo mode =============== */ void R_SetupView (void) { Fog_SetupFrame (); //johnfitz // build the transformation matrix for the given view angles VectorCopy (r_refdef.vieworg, r_origin); AngleVectors (r_refdef.viewangles, vpn, vright, vup); // current viewleaf r_oldviewleaf = r_viewleaf; r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); V_SetContentsColor (r_viewleaf->contents); V_CalcBlend (); r_cache_thrash = false; //johnfitz -- calculate r_fovx and r_fovy here r_fovx = r_refdef.fov_x; r_fovy = r_refdef.fov_y; if (r_waterwarp.value) { int contents = Mod_PointInLeaf (r_origin, cl.worldmodel)->contents; if (contents == CONTENTS_WATER || contents == CONTENTS_SLIME || contents == CONTENTS_LAVA) { //variance is a percentage of width, where width = 2 * tan(fov / 2) otherwise the effect is too dramatic at high FOV and too subtle at low FOV. what a mess! r_fovx = atan(tan(DEG2RAD(r_refdef.fov_x) / 2) * (0.97 + sin(cl.time * 1.5) * 0.03)) * 2 / M_PI_DIV_180; r_fovy = atan(tan(DEG2RAD(r_refdef.fov_y) / 2) * (1.03 - sin(cl.time * 1.5) * 0.03)) * 2 / M_PI_DIV_180; } } //johnfitz R_SetFrustum (r_fovx, r_fovy); //johnfitz -- use r_fov* vars R_MarkSurfaces (); //johnfitz -- create texture chains from PVS R_CullSurfaces (); //johnfitz -- do after R_SetFrustum and R_MarkSurfaces R_UpdateWarpTextures (); //johnfitz -- do this before R_Clear R_Clear (); //johnfitz -- cheat-protect some draw modes r_drawflat_cheatsafe = r_fullbright_cheatsafe = r_lightmap_cheatsafe = false; r_drawworld_cheatsafe = true; if (cl.maxclients == 1) { if (!r_drawworld.value) r_drawworld_cheatsafe = false; if (r_drawflat.value) r_drawflat_cheatsafe = true; else if (r_fullbright.value || !cl.worldmodel->lightdata) r_fullbright_cheatsafe = true; else if (r_lightmap.value) r_lightmap_cheatsafe = true; } //johnfitz } //============================================================================== // // RENDER VIEW // //============================================================================== /* ============= R_DrawEntitiesOnList ============= */ void R_DrawEntitiesOnList (qboolean alphapass) //johnfitz -- added parameter { int i; if (!r_drawentities.value) return; //johnfitz -- sprites are not a special case for (i=0 ; i<cl_numvisedicts ; i++) { currententity = cl_visedicts[i]; //johnfitz -- if alphapass is true, draw only alpha entites this time //if alphapass is false, draw only nonalpha entities this time if ((ENTALPHA_DECODE(currententity->alpha) < 1 && !alphapass) || (ENTALPHA_DECODE(currententity->alpha) == 1 && alphapass)) continue; //johnfitz -- chasecam if (currententity == &cl_entities[cl.viewentity]) currententity->angles[0] *= 0.3; //johnfitz switch (currententity->model->type) { case mod_alias: R_DrawAliasModel (currententity); break; case mod_brush: R_DrawBrushModel (currententity); break; case mod_sprite: R_DrawSpriteModel (currententity); break; } } } /* ============= R_DrawViewModel -- johnfitz -- gutted ============= */ void R_DrawViewModel (void) { if (!r_drawviewmodel.value || !r_drawentities.value || chase_active.value) return; if (cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0) return; currententity = &cl.viewent; if (!currententity->model) return; //johnfitz -- this fixes a crash if (currententity->model->type != mod_alias) return; //johnfitz // hack the depth range to prevent view model from poking into walls glDepthRange (0, 0.3); R_DrawAliasModel (currententity); glDepthRange (0, 1); } /* ================ R_EmitWirePoint -- johnfitz -- draws a wireframe cross shape for point entities ================ */ void R_EmitWirePoint (vec3_t origin) { int size=8; glBegin (GL_LINES); glVertex3f (origin[0]-size, origin[1], origin[2]); glVertex3f (origin[0]+size, origin[1], origin[2]); glVertex3f (origin[0], origin[1]-size, origin[2]); glVertex3f (origin[0], origin[1]+size, origin[2]); glVertex3f (origin[0], origin[1], origin[2]-size); glVertex3f (origin[0], origin[1], origin[2]+size); glEnd (); } /* ================ R_EmitWireBox -- johnfitz -- draws one axis aligned bounding box ================ */ void R_EmitWireBox (vec3_t mins, vec3_t maxs) { glBegin (GL_QUAD_STRIP); glVertex3f (mins[0], mins[1], mins[2]); glVertex3f (mins[0], mins[1], maxs[2]); glVertex3f (maxs[0], mins[1], mins[2]); glVertex3f (maxs[0], mins[1], maxs[2]); glVertex3f (maxs[0], maxs[1], mins[2]); glVertex3f (maxs[0], maxs[1], maxs[2]); glVertex3f (mins[0], maxs[1], mins[2]); glVertex3f (mins[0], maxs[1], maxs[2]); glVertex3f (mins[0], mins[1], mins[2]); glVertex3f (mins[0], mins[1], maxs[2]); glEnd (); } /* ================ R_ShowBoundingBoxes -- johnfitz draw bounding boxes -- the server-side boxes, not the renderer cullboxes ================ */ void R_ShowBoundingBoxes (void) { extern edict_t *sv_player; vec3_t mins,maxs; edict_t *ed; int i; if (!r_showbboxes.value || cl.maxclients > 1 || !r_drawentities.value || !sv.active) return; glDisable (GL_DEPTH_TEST); glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); GL_PolygonOffset (OFFSET_SHOWTRIS); glDisable (GL_TEXTURE_2D); glDisable (GL_CULL_FACE); glColor3f (1,1,1); for (i=0, ed=NEXT_EDICT(sv.edicts) ; i<sv.num_edicts ; i++, ed=NEXT_EDICT(ed)) { if (ed == sv_player) continue; //don't draw player's own bbox // if (r_showbboxes.value != 2) // if (!SV_VisibleToClient (sv_player, ed, sv.worldmodel)) // continue; //don't draw if not in pvs if (ed->v.mins[0] == ed->v.maxs[0] && ed->v.mins[1] == ed->v.maxs[1] && ed->v.mins[2] == ed->v.maxs[2]) { //point entity R_EmitWirePoint (ed->v.origin); } else { //box entity VectorAdd (ed->v.mins, ed->v.origin, mins); VectorAdd (ed->v.maxs, ed->v.origin, maxs); R_EmitWireBox (mins, maxs); } } glColor3f (1,1,1); glEnable (GL_TEXTURE_2D); glEnable (GL_CULL_FACE); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); GL_PolygonOffset (OFFSET_NONE); glEnable (GL_DEPTH_TEST); Sbar_Changed (); //so we don't get dots collecting on the statusbar } /* ================ R_ShowTris -- johnfitz ================ */ void R_ShowTris (void) { extern cvar_t r_particles; int i; if (r_showtris.value < 1 || r_showtris.value > 2 || cl.maxclients > 1) return; if (r_showtris.value == 1) glDisable (GL_DEPTH_TEST); glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); GL_PolygonOffset (OFFSET_SHOWTRIS); glDisable (GL_TEXTURE_2D); glColor3f (1,1,1); // glEnable (GL_BLEND); // glBlendFunc (GL_ONE, GL_ONE); if (r_drawworld.value) { R_DrawWorld_ShowTris (); } if (r_drawentities.value) { for (i=0 ; i<cl_numvisedicts ; i++) { currententity = cl_visedicts[i]; if (currententity == &cl_entities[cl.viewentity]) // chasecam currententity->angles[0] *= 0.3; switch (currententity->model->type) { case mod_brush: R_DrawBrushModel_ShowTris (currententity); break; case mod_alias: R_DrawAliasModel_ShowTris (currententity); break; case mod_sprite: R_DrawSpriteModel (currententity); break; default: break; } } // viewmodel currententity = &cl.viewent; if (r_drawviewmodel.value && !chase_active.value && cl.stats[STAT_HEALTH] > 0 && !(cl.items & IT_INVISIBILITY) && currententity->model && currententity->model->type == mod_alias) { glDepthRange (0, 0.3); R_DrawAliasModel_ShowTris (currententity); glDepthRange (0, 1); } } if (r_particles.value) { R_DrawParticles_ShowTris (); } // glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glDisable (GL_BLEND); glColor3f (1,1,1); glEnable (GL_TEXTURE_2D); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); GL_PolygonOffset (OFFSET_NONE); if (r_showtris.value == 1) glEnable (GL_DEPTH_TEST); Sbar_Changed (); //so we don't get dots collecting on the statusbar } /* ================ R_DrawShadows ================ */ void R_DrawShadows (void) { int i; if (!r_shadows.value || !r_drawentities.value || r_drawflat_cheatsafe || r_lightmap_cheatsafe) return; // Use stencil buffer to prevent self-intersecting shadows, from Baker (MarkV) if (gl_stencilbits) { glClear(GL_STENCIL_BUFFER_BIT); glStencilFunc(GL_EQUAL, 0, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glEnable(GL_STENCIL_TEST); } for (i=0 ; i<cl_numvisedicts ; i++) { currententity = cl_visedicts[i]; if (currententity->model->type != mod_alias) continue; if (currententity == &cl.viewent) return; GL_DrawAliasShadow (currententity); } if (gl_stencilbits) { glDisable(GL_STENCIL_TEST); } } /* ================ R_RenderScene ================ */ void R_RenderScene (void) { R_SetupScene (); //johnfitz -- this does everything that should be done once per call to RenderScene Fog_EnableGFog (); //johnfitz Sky_DrawSky (); //johnfitz R_DrawWorld (); S_ExtraUpdate (); // don't let sound get messed up if going slow R_DrawShadows (); //johnfitz -- render entity shadows R_DrawEntitiesOnList (false); //johnfitz -- false means this is the pass for nonalpha entities R_DrawWorld_Water (); //johnfitz -- drawn here since they might have transparency R_DrawEntitiesOnList (true); //johnfitz -- true means this is the pass for alpha entities R_RenderDlights (); //triangle fan dlights -- johnfitz -- moved after water R_DrawParticles (); Fog_DisableGFog (); //johnfitz R_DrawViewModel (); //johnfitz -- moved here from R_RenderView R_ShowTris (); //johnfitz R_ShowBoundingBoxes (); //johnfitz } /* ================ R_RenderView ================ */ void R_RenderView (void) { double time1, time2; if (r_norefresh.value) return; if (!cl.worldmodel) Sys_Error ("R_RenderView: NULL worldmodel"); time1 = 0; /* avoid compiler warning */ if (r_speeds.value) { glFinish (); time1 = Sys_DoubleTime (); //johnfitz -- rendering statistics rs_brushpolys = rs_aliaspolys = rs_skypolys = rs_particles = rs_fogpolys = rs_megatexels = rs_dynamiclightmaps = rs_aliaspasses = rs_skypasses = rs_brushpasses = 0; } else if (gl_finish.value) glFinish (); R_SetupView (); //johnfitz -- this does everything that should be done once per frame //johnfitz -- stereo rendering -- full of hacky goodness if (r_stereo.value) { float eyesep = CLAMP(-8.0f, r_stereo.value, 8.0f); float fdepth = CLAMP(32.0f, r_stereodepth.value, 1024.0f); AngleVectors (r_refdef.viewangles, vpn, vright, vup); //render left eye (red) glColorMask(1, 0, 0, 1); VectorMA (r_refdef.vieworg, -0.5f * eyesep, vright, r_refdef.vieworg); frustum_skew = 0.5 * eyesep * NEARCLIP / fdepth; srand((int) (cl.time * 1000)); //sync random stuff between eyes R_RenderScene (); //render right eye (cyan) glClear (GL_DEPTH_BUFFER_BIT); glColorMask(0, 1, 1, 1); VectorMA (r_refdef.vieworg, 1.0f * eyesep, vright, r_refdef.vieworg); frustum_skew = -frustum_skew; srand((int) (cl.time * 1000)); //sync random stuff between eyes R_RenderScene (); //restore glColorMask(1, 1, 1, 1); VectorMA (r_refdef.vieworg, -0.5f * eyesep, vright, r_refdef.vieworg); frustum_skew = 0.0f; } else { R_RenderScene (); } //johnfitz //johnfitz -- modified r_speeds output time2 = Sys_DoubleTime (); if (r_pos.value) Con_Printf ("x %i y %i z %i (pitch %i yaw %i roll %i)\n", (int)cl_entities[cl.viewentity].origin[0], (int)cl_entities[cl.viewentity].origin[1], (int)cl_entities[cl.viewentity].origin[2], (int)cl.viewangles[PITCH], (int)cl.viewangles[YAW], (int)cl.viewangles[ROLL]); else if (r_speeds.value == 2) Con_Printf ("%3i ms %4i/%4i wpoly %4i/%4i epoly %3i lmap %4i/%4i sky %1.1f mtex\n", (int)((time2-time1)*1000), rs_brushpolys, rs_brushpasses, rs_aliaspolys, rs_aliaspasses, rs_dynamiclightmaps, rs_skypolys, rs_skypasses, TexMgr_FrameUsage ()); else if (r_speeds.value) Con_Printf ("%3i ms %4i wpoly %4i epoly %3i lmap\n", (int)((time2-time1)*1000), rs_brushpolys, rs_aliaspolys, rs_dynamiclightmaps); //johnfitz } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/pr_comp.h�������������������������������������������������������������������0000644�0000000�0000000�00000006160�12407762022�015334� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __PR_COMP_H #define __PR_COMP_H // this file is shared by quake and qcc typedef int func_t; typedef int string_t; typedef enum { ev_bad = -1, ev_void = 0, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer } etype_t; #define OFS_NULL 0 #define OFS_RETURN 1 #define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors #define OFS_PARM1 7 #define OFS_PARM2 10 #define OFS_PARM3 13 #define OFS_PARM4 16 #define OFS_PARM5 19 #define OFS_PARM6 22 #define OFS_PARM7 25 #define RESERVED_OFS 28 enum { OP_DONE, OP_MUL_F, OP_MUL_V, OP_MUL_FV, OP_MUL_VF, OP_DIV_F, OP_ADD_F, OP_ADD_V, OP_SUB_F, OP_SUB_V, OP_EQ_F, OP_EQ_V, OP_EQ_S, OP_EQ_E, OP_EQ_FNC, OP_NE_F, OP_NE_V, OP_NE_S, OP_NE_E, OP_NE_FNC, OP_LE, OP_GE, OP_LT, OP_GT, OP_LOAD_F, OP_LOAD_V, OP_LOAD_S, OP_LOAD_ENT, OP_LOAD_FLD, OP_LOAD_FNC, OP_ADDRESS, OP_STORE_F, OP_STORE_V, OP_STORE_S, OP_STORE_ENT, OP_STORE_FLD, OP_STORE_FNC, OP_STOREP_F, OP_STOREP_V, OP_STOREP_S, OP_STOREP_ENT, OP_STOREP_FLD, OP_STOREP_FNC, OP_RETURN, OP_NOT_F, OP_NOT_V, OP_NOT_S, OP_NOT_ENT, OP_NOT_FNC, OP_IF, OP_IFNOT, OP_CALL0, OP_CALL1, OP_CALL2, OP_CALL3, OP_CALL4, OP_CALL5, OP_CALL6, OP_CALL7, OP_CALL8, OP_STATE, OP_GOTO, OP_AND, OP_OR, OP_BITAND, OP_BITOR }; typedef struct statement_s { unsigned short op; short a, b, c; } dstatement_t; typedef struct { unsigned short type; // if DEF_SAVEGLOBAL bit is set // the variable needs to be saved in savegames unsigned short ofs; int s_name; } ddef_t; #define DEF_SAVEGLOBAL (1<<15) #define MAX_PARMS 8 typedef struct { int first_statement; // negative numbers are builtins int parm_start; int locals; // total ints of parms + locals int profile; // runtime int s_name; int s_file; // source file defined in int numparms; byte parm_size[MAX_PARMS]; } dfunction_t; #define PROG_VERSION 6 typedef struct { int version; int crc; // check of header file int ofs_statements; int numstatements; // statement 0 is an error int ofs_globaldefs; int numglobaldefs; int ofs_fielddefs; int numfielddefs; int ofs_functions; int numfunctions; // function 0 is an empty int ofs_strings; int numstrings; // first string is a null string int ofs_globals; int numglobals; int entityfields; } dprograms_t; #endif /* __PR_COMP_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_texmgr.h�����������������������������������������������������������������0000644�0000000�0000000�00000010375�12633216330�015665� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GL_TEXMAN_H #define _GL_TEXMAN_H //gl_texmgr.h -- fitzquake's texture manager. manages opengl texture images #define TEXPREF_NONE 0x0000 #define TEXPREF_MIPMAP 0x0001 // generate mipmaps // TEXPREF_NEAREST and TEXPREF_LINEAR aren't supposed to be ORed with TEX_MIPMAP #define TEXPREF_LINEAR 0x0002 // force linear #define TEXPREF_NEAREST 0x0004 // force nearest #define TEXPREF_ALPHA 0x0008 // allow alpha #define TEXPREF_PAD 0x0010 // allow padding #define TEXPREF_PERSIST 0x0020 // never free #define TEXPREF_OVERWRITE 0x0040 // overwrite existing same-name texture #define TEXPREF_NOPICMIP 0x0080 // always load full-sized #define TEXPREF_FULLBRIGHT 0x0100 // use fullbright mask palette #define TEXPREF_NOBRIGHT 0x0200 // use nobright mask palette #define TEXPREF_CONCHARS 0x0400 // use conchars palette #define TEXPREF_WARPIMAGE 0x0800 // resize this texture when warpimagesize changes enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA}; typedef uintptr_t src_offset_t; typedef struct gltexture_s { //managed by texture manager GLuint texnum; struct gltexture_s *next; qmodel_t *owner; //managed by image loading char name[64]; unsigned int width; //size of image as it exists in opengl unsigned int height; //size of image as it exists in opengl unsigned int flags; char source_file[MAX_QPATH]; //relative filepath to data source, or "" if source is in memory src_offset_t source_offset; //byte offset into file, or memory address enum srcformat source_format; //format of pixel data (indexed, lightmap, or rgba) unsigned int source_width; //size of image in source data unsigned int source_height; //size of image in source data unsigned short source_crc; //generated by source data before modifications char shirt; //0-13 shirt color, or -1 if never colormapped char pants; //0-13 pants color, or -1 if never colormapped //used for rendering int visframe; //matches r_framecount if texture was bound this frame } gltexture_t; extern gltexture_t *notexture; extern gltexture_t *nulltexture; extern unsigned int d_8to24table[256]; extern unsigned int d_8to24table_fbright[256]; extern unsigned int d_8to24table_nobright[256]; extern unsigned int d_8to24table_conchars[256]; extern unsigned int d_8to24table_shirt[256]; extern unsigned int d_8to24table_pants[256]; // TEXTURE MANAGER float TexMgr_FrameUsage (void); gltexture_t *TexMgr_FindTexture (qmodel_t *owner, const char *name); gltexture_t *TexMgr_NewTexture (void); void TexMgr_FreeTexture (gltexture_t *kill); void TexMgr_FreeTextures (unsigned int flags, unsigned int mask); void TexMgr_FreeTexturesForOwner (qmodel_t *owner); void TexMgr_NewGame (void); void TexMgr_Init (void); void TexMgr_DeleteTextureObjects (void); // IMAGE LOADING gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int height, enum srcformat format, byte *data, const char *source_file, src_offset_t source_offset, unsigned flags); void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants); void TexMgr_ReloadImages (void); void TexMgr_ReloadNobrightImages (void); int TexMgr_Pad(int s); int TexMgr_SafeTextureSize (int s); int TexMgr_PadConditional (int s); // TEXTURE BINDING & TEXTURE UNIT SWITCHING void GL_SelectTexture (GLenum target); void GL_DisableMultitexture (void); //selects texture unit 0 void GL_EnableMultitexture (void); //selects texture unit 1 void GL_Bind (gltexture_t *texture); void GL_ClearBindings (void); #endif /* _GL_TEXMAN_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/in_sdl.c��������������������������������������������������������������������0000644�0000000�0000000�00000043352�12417266025�015147� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif static qboolean textmode; static cvar_t in_debugkeys = {"in_debugkeys", "0", CVAR_NONE}; #ifdef __APPLE__ /* Mouse acceleration needs to be disabled on OS X */ #define MACOS_X_ACCELERATION_HACK #endif #ifdef MACOS_X_ACCELERATION_HACK #include <IOKit/IOTypes.h> #include <IOKit/hidsystem/IOHIDLib.h> #include <IOKit/hidsystem/IOHIDParameter.h> #include <IOKit/hidsystem/event_status_driver.h> #endif static qboolean no_mouse = false; static int buttonremap[] = { K_MOUSE1, K_MOUSE3, /* right button */ K_MOUSE2, /* middle button */ #if !defined(USE_SDL2) /* mousewheel up/down not counted as buttons in SDL2 */ K_MWHEELUP, K_MWHEELDOWN, #endif K_MOUSE4, K_MOUSE5 }; /* total accumulated mouse movement since last frame */ static int total_dx, total_dy = 0; static int IN_FilterMouseEvents (const SDL_Event *event) { switch (event->type) { case SDL_MOUSEMOTION: // case SDL_MOUSEBUTTONDOWN: // case SDL_MOUSEBUTTONUP: return 0; } return 1; } #if defined(USE_SDL2) static int IN_SDL2_FilterMouseEvents (void *userdata, SDL_Event *event) { return IN_FilterMouseEvents (event); } #endif static void IN_BeginIgnoringMouseEvents() { #if defined(USE_SDL2) SDL_EventFilter currentFilter = NULL; void *currentUserdata = NULL; SDL_GetEventFilter(¤tFilter, ¤tUserdata); if (currentFilter != IN_SDL2_FilterMouseEvents) SDL_SetEventFilter(IN_SDL2_FilterMouseEvents, NULL); #else if (SDL_GetEventFilter() != IN_FilterMouseEvents) SDL_SetEventFilter(IN_FilterMouseEvents); #endif } static void IN_EndIgnoringMouseEvents() { #if defined(USE_SDL2) SDL_EventFilter currentFilter; void *currentUserdata; if (SDL_GetEventFilter(¤tFilter, ¤tUserdata) == SDL_TRUE) SDL_SetEventFilter(NULL, NULL); #else if (SDL_GetEventFilter() != NULL) SDL_SetEventFilter(NULL); #endif } #ifdef MACOS_X_ACCELERATION_HACK static cvar_t in_disablemacosxmouseaccel = {"in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE}; static double originalMouseSpeed = -1.0; static io_connect_t IN_GetIOHandle(void) { io_connect_t iohandle = MACH_PORT_NULL; io_service_t iohidsystem = MACH_PORT_NULL; mach_port_t masterport; kern_return_t status; status = IOMasterPort(MACH_PORT_NULL, &masterport); if (status != KERN_SUCCESS) return 0; iohidsystem = IORegistryEntryFromPath(masterport, kIOServicePlane ":/IOResources/IOHIDSystem"); if (!iohidsystem) return 0; status = IOServiceOpen(iohidsystem, mach_task_self(), kIOHIDParamConnectType, &iohandle); IOObjectRelease(iohidsystem); return iohandle; } static void IN_DisableOSXMouseAccel (void) { io_connect_t mouseDev = IN_GetIOHandle(); if (mouseDev != 0) { if (IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess) { if (IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess) { Cvar_Set("in_disablemacosxmouseaccel", "0"); Con_Printf("WARNING: Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n"); } } else { Cvar_Set("in_disablemacosxmouseaccel", "0"); Con_Printf("WARNING: Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n"); } IOServiceClose(mouseDev); } else { Cvar_Set("in_disablemacosxmouseaccel", "0"); Con_Printf("WARNING: Could not disable mouse acceleration (failed at IO_GetIOHandle).\n"); } } static void IN_ReenableOSXMouseAccel (void) { io_connect_t mouseDev = IN_GetIOHandle(); if (mouseDev != 0) { if (IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess) Con_Printf("WARNING: Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n"); IOServiceClose(mouseDev); } else { Con_Printf("WARNING: Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n"); } originalMouseSpeed = -1; } #endif /* MACOS_X_ACCELERATION_HACK */ void IN_Activate (void) { if (no_mouse) return; #ifdef MACOS_X_ACCELERATION_HACK /* Save the status of mouse acceleration */ if (originalMouseSpeed == -1 && in_disablemacosxmouseaccel.value) IN_DisableOSXMouseAccel(); #endif #if defined(USE_SDL2) if (SDL_SetRelativeMouseMode(SDL_TRUE) != 0) { Con_Printf("WARNING: SDL_SetRelativeMouseMode(SDL_TRUE) failed.\n"); } #else if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON) { SDL_WM_GrabInput(SDL_GRAB_ON); if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON) Con_Printf("WARNING: SDL_WM_GrabInput(SDL_GRAB_ON) failed.\n"); } if (SDL_ShowCursor(SDL_QUERY) != SDL_DISABLE) { SDL_ShowCursor(SDL_DISABLE); if (SDL_ShowCursor(SDL_QUERY) != SDL_DISABLE) Con_Printf("WARNING: SDL_ShowCursor(SDL_DISABLE) failed.\n"); } #endif IN_EndIgnoringMouseEvents(); total_dx = 0; total_dy = 0; } void IN_Deactivate (qboolean free_cursor) { if (no_mouse) return; #ifdef MACOS_X_ACCELERATION_HACK if (originalMouseSpeed != -1) IN_ReenableOSXMouseAccel(); #endif if (free_cursor) { #if defined(USE_SDL2) SDL_SetRelativeMouseMode(SDL_FALSE); #else if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_OFF) { SDL_WM_GrabInput(SDL_GRAB_OFF); if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_OFF) Con_Printf("WARNING: SDL_WM_GrabInput(SDL_GRAB_OFF) failed.\n"); } if (SDL_ShowCursor(SDL_QUERY) != SDL_ENABLE) { SDL_ShowCursor(SDL_ENABLE); if (SDL_ShowCursor(SDL_QUERY) != SDL_ENABLE) Con_Printf("WARNING: SDL_ShowCursor(SDL_ENABLE) failed.\n"); } #endif } /* discard all mouse events when input is deactivated */ IN_BeginIgnoringMouseEvents(); } void IN_Init (void) { textmode = Key_TextEntry(); #if !defined(USE_SDL2) SDL_EnableUNICODE (textmode); if (SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL) == -1) Con_Printf("Warning: SDL_EnableKeyRepeat() failed.\n"); #else if (textmode) SDL_StartTextInput(); else SDL_StopTextInput(); #endif if (safemode || COM_CheckParm("-nomouse")) { no_mouse = true; /* discard all mouse events when input is deactivated */ IN_BeginIgnoringMouseEvents(); } #ifdef MACOS_X_ACCELERATION_HACK Cvar_RegisterVariable(&in_disablemacosxmouseaccel); #endif Cvar_RegisterVariable(&in_debugkeys); IN_Activate(); } void IN_Shutdown (void) { IN_Deactivate(true); } void IN_Commands (void) { /* TODO: implement this for joystick support */ } extern cvar_t cl_maxpitch; /* johnfitz -- variable pitch clamping */ extern cvar_t cl_minpitch; /* johnfitz -- variable pitch clamping */ void IN_MouseMove(int dx, int dy) { total_dx += dx; total_dy += dy; } void IN_Move (usercmd_t *cmd) { int dmx, dmy; dmx = total_dx * sensitivity.value; dmy = total_dy * sensitivity.value; total_dx = 0; total_dy = 0; if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) )) cmd->sidemove += m_side.value * dmx; else cl.viewangles[YAW] -= m_yaw.value * dmx; if (in_mlook.state & 1) { if (dmx || dmy) V_StopPitchDrift (); } if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) { cl.viewangles[PITCH] += m_pitch.value * dmy; /* johnfitz -- variable pitch clamping */ if (cl.viewangles[PITCH] > cl_maxpitch.value) cl.viewangles[PITCH] = cl_maxpitch.value; if (cl.viewangles[PITCH] < cl_minpitch.value) cl.viewangles[PITCH] = cl_minpitch.value; } else { if ((in_strafe.state & 1) && noclip_anglehack) cmd->upmove -= m_forward.value * dmy; else cmd->forwardmove -= m_forward.value * dmy; } } void IN_ClearStates (void) { } void IN_UpdateInputMode (void) { qboolean want_textmode = Key_TextEntry(); if (textmode != want_textmode) { textmode = want_textmode; #if !defined(USE_SDL2) SDL_EnableUNICODE(textmode); #else if (textmode) SDL_StartTextInput(); else SDL_StopTextInput(); #endif } } #if !defined(USE_SDL2) static inline int IN_SDL_KeysymToQuakeKey(SDLKey sym) { if (sym > SDLK_SPACE && sym < SDLK_DELETE) return sym; switch (sym) { case SDLK_TAB: return K_TAB; case SDLK_RETURN: return K_ENTER; case SDLK_ESCAPE: return K_ESCAPE; case SDLK_SPACE: return K_SPACE; case SDLK_BACKSPACE: return K_BACKSPACE; case SDLK_UP: return K_UPARROW; case SDLK_DOWN: return K_DOWNARROW; case SDLK_LEFT: return K_LEFTARROW; case SDLK_RIGHT: return K_RIGHTARROW; case SDLK_LALT: return K_ALT; case SDLK_RALT: return K_ALT; case SDLK_LCTRL: return K_CTRL; case SDLK_RCTRL: return K_CTRL; case SDLK_LSHIFT: return K_SHIFT; case SDLK_RSHIFT: return K_SHIFT; case SDLK_F1: return K_F1; case SDLK_F2: return K_F2; case SDLK_F3: return K_F3; case SDLK_F4: return K_F4; case SDLK_F5: return K_F5; case SDLK_F6: return K_F6; case SDLK_F7: return K_F7; case SDLK_F8: return K_F8; case SDLK_F9: return K_F9; case SDLK_F10: return K_F10; case SDLK_F11: return K_F11; case SDLK_F12: return K_F12; case SDLK_INSERT: return K_INS; case SDLK_DELETE: return K_DEL; case SDLK_PAGEDOWN: return K_PGDN; case SDLK_PAGEUP: return K_PGUP; case SDLK_HOME: return K_HOME; case SDLK_END: return K_END; case SDLK_NUMLOCK: return K_KP_NUMLOCK; case SDLK_KP_DIVIDE: return K_KP_SLASH; case SDLK_KP_MULTIPLY: return K_KP_STAR; case SDLK_KP_MINUS:return K_KP_MINUS; case SDLK_KP7: return K_KP_HOME; case SDLK_KP8: return K_KP_UPARROW; case SDLK_KP9: return K_KP_PGUP; case SDLK_KP_PLUS: return K_KP_PLUS; case SDLK_KP4: return K_KP_LEFTARROW; case SDLK_KP5: return K_KP_5; case SDLK_KP6: return K_KP_RIGHTARROW; case SDLK_KP1: return K_KP_END; case SDLK_KP2: return K_KP_DOWNARROW; case SDLK_KP3: return K_KP_PGDN; case SDLK_KP_ENTER: return K_KP_ENTER; case SDLK_KP0: return K_KP_INS; case SDLK_KP_PERIOD: return K_KP_DEL; case SDLK_LMETA: return K_COMMAND; case SDLK_RMETA: return K_COMMAND; case SDLK_BREAK: return K_PAUSE; case SDLK_PAUSE: return K_PAUSE; case SDLK_WORLD_18: return '~'; // the '²' key default: return 0; } } #endif #if defined(USE_SDL2) static inline int IN_SDL2_ScancodeToQuakeKey(SDL_Scancode scancode) { switch (scancode) { case SDL_SCANCODE_TAB: return K_TAB; case SDL_SCANCODE_RETURN: return K_ENTER; case SDL_SCANCODE_RETURN2: return K_ENTER; case SDL_SCANCODE_ESCAPE: return K_ESCAPE; case SDL_SCANCODE_SPACE: return K_SPACE; case SDL_SCANCODE_A: return 'a'; case SDL_SCANCODE_B: return 'b'; case SDL_SCANCODE_C: return 'c'; case SDL_SCANCODE_D: return 'd'; case SDL_SCANCODE_E: return 'e'; case SDL_SCANCODE_F: return 'f'; case SDL_SCANCODE_G: return 'g'; case SDL_SCANCODE_H: return 'h'; case SDL_SCANCODE_I: return 'i'; case SDL_SCANCODE_J: return 'j'; case SDL_SCANCODE_K: return 'k'; case SDL_SCANCODE_L: return 'l'; case SDL_SCANCODE_M: return 'm'; case SDL_SCANCODE_N: return 'n'; case SDL_SCANCODE_O: return 'o'; case SDL_SCANCODE_P: return 'p'; case SDL_SCANCODE_Q: return 'q'; case SDL_SCANCODE_R: return 'r'; case SDL_SCANCODE_S: return 's'; case SDL_SCANCODE_T: return 't'; case SDL_SCANCODE_U: return 'u'; case SDL_SCANCODE_V: return 'v'; case SDL_SCANCODE_W: return 'w'; case SDL_SCANCODE_X: return 'x'; case SDL_SCANCODE_Y: return 'y'; case SDL_SCANCODE_Z: return 'z'; case SDL_SCANCODE_1: return '1'; case SDL_SCANCODE_2: return '2'; case SDL_SCANCODE_3: return '3'; case SDL_SCANCODE_4: return '4'; case SDL_SCANCODE_5: return '5'; case SDL_SCANCODE_6: return '6'; case SDL_SCANCODE_7: return '7'; case SDL_SCANCODE_8: return '8'; case SDL_SCANCODE_9: return '9'; case SDL_SCANCODE_0: return '0'; case SDL_SCANCODE_MINUS: return '-'; case SDL_SCANCODE_EQUALS: return '='; case SDL_SCANCODE_LEFTBRACKET: return '['; case SDL_SCANCODE_RIGHTBRACKET: return ']'; case SDL_SCANCODE_BACKSLASH: return '\\'; case SDL_SCANCODE_NONUSHASH: return '#'; case SDL_SCANCODE_SEMICOLON: return ';'; case SDL_SCANCODE_APOSTROPHE: return '\''; case SDL_SCANCODE_GRAVE: return '`'; case SDL_SCANCODE_COMMA: return ','; case SDL_SCANCODE_PERIOD: return '.'; case SDL_SCANCODE_SLASH: return '/'; case SDL_SCANCODE_NONUSBACKSLASH: return '\\'; case SDL_SCANCODE_BACKSPACE: return K_BACKSPACE; case SDL_SCANCODE_UP: return K_UPARROW; case SDL_SCANCODE_DOWN: return K_DOWNARROW; case SDL_SCANCODE_LEFT: return K_LEFTARROW; case SDL_SCANCODE_RIGHT: return K_RIGHTARROW; case SDL_SCANCODE_LALT: return K_ALT; case SDL_SCANCODE_RALT: return K_ALT; case SDL_SCANCODE_LCTRL: return K_CTRL; case SDL_SCANCODE_RCTRL: return K_CTRL; case SDL_SCANCODE_LSHIFT: return K_SHIFT; case SDL_SCANCODE_RSHIFT: return K_SHIFT; case SDL_SCANCODE_F1: return K_F1; case SDL_SCANCODE_F2: return K_F2; case SDL_SCANCODE_F3: return K_F3; case SDL_SCANCODE_F4: return K_F4; case SDL_SCANCODE_F5: return K_F5; case SDL_SCANCODE_F6: return K_F6; case SDL_SCANCODE_F7: return K_F7; case SDL_SCANCODE_F8: return K_F8; case SDL_SCANCODE_F9: return K_F9; case SDL_SCANCODE_F10: return K_F10; case SDL_SCANCODE_F11: return K_F11; case SDL_SCANCODE_F12: return K_F12; case SDL_SCANCODE_INSERT: return K_INS; case SDL_SCANCODE_DELETE: return K_DEL; case SDL_SCANCODE_PAGEDOWN: return K_PGDN; case SDL_SCANCODE_PAGEUP: return K_PGUP; case SDL_SCANCODE_HOME: return K_HOME; case SDL_SCANCODE_END: return K_END; case SDL_SCANCODE_NUMLOCKCLEAR: return K_KP_NUMLOCK; case SDL_SCANCODE_KP_DIVIDE: return K_KP_SLASH; case SDL_SCANCODE_KP_MULTIPLY: return K_KP_STAR; case SDL_SCANCODE_KP_MINUS: return K_KP_MINUS; case SDL_SCANCODE_KP_7: return K_KP_HOME; case SDL_SCANCODE_KP_8: return K_KP_UPARROW; case SDL_SCANCODE_KP_9: return K_KP_PGUP; case SDL_SCANCODE_KP_PLUS: return K_KP_PLUS; case SDL_SCANCODE_KP_4: return K_KP_LEFTARROW; case SDL_SCANCODE_KP_5: return K_KP_5; case SDL_SCANCODE_KP_6: return K_KP_RIGHTARROW; case SDL_SCANCODE_KP_1: return K_KP_END; case SDL_SCANCODE_KP_2: return K_KP_DOWNARROW; case SDL_SCANCODE_KP_3: return K_KP_PGDN; case SDL_SCANCODE_KP_ENTER: return K_KP_ENTER; case SDL_SCANCODE_KP_0: return K_KP_INS; case SDL_SCANCODE_KP_PERIOD: return K_KP_DEL; case SDL_SCANCODE_LGUI: return K_COMMAND; case SDL_SCANCODE_RGUI: return K_COMMAND; case SDL_SCANCODE_PAUSE: return K_PAUSE; default: return 0; } } #endif #if defined(USE_SDL2) static void IN_DebugTextEvent(SDL_Event *event) { Con_Printf ("SDL_TEXTINPUT '%s'\n", event->text.text); } #endif static void IN_DebugKeyEvent(SDL_Event *event) { const char *eventtype = (event->key.state == SDL_PRESSED) ? "SDL_KEYDOWN" : "SDL_KEYUP"; #if defined(USE_SDL2) Con_Printf ("%s scancode: '%s' keycode: '%s'\n", eventtype, SDL_GetScancodeName(event->key.keysym.scancode), SDL_GetKeyName(event->key.keysym.sym)); #else Con_Printf ("%s sym: '%s' unicode: %04x\n", eventtype, SDL_GetKeyName(event->key.keysym.sym), (int)event->key.keysym.unicode); #endif } void IN_SendKeyEvents (void) { SDL_Event event; int key; qboolean down; while (SDL_PollEvent(&event)) { switch (event.type) { #if defined(USE_SDL2) case SDL_WINDOWEVENT: if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) S_UnblockSound(); else if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) S_BlockSound(); break; #else case SDL_ACTIVEEVENT: if (event.active.state & (SDL_APPINPUTFOCUS|SDL_APPACTIVE)) { if (event.active.gain) S_UnblockSound(); else S_BlockSound(); } break; #endif #if defined(USE_SDL2) case SDL_TEXTINPUT: if (in_debugkeys.value) IN_DebugTextEvent(&event); // SDL2: We use SDL_TEXTINPUT for typing in the console / chat. // SDL2 uses the local keyboard layout and handles modifiers // (shift for uppercase, etc.) for us. { unsigned char *ch; for (ch = (unsigned char *)event.text.text; *ch; ch++) if ((*ch & ~0x7F) == 0) Char_Event (*ch); } break; #endif case SDL_KEYDOWN: case SDL_KEYUP: down = (event.key.state == SDL_PRESSED); if (in_debugkeys.value) IN_DebugKeyEvent(&event); #if defined(USE_SDL2) // SDL2: we interpret the keyboard as the US layout, so keybindings // are based on key position, not the label on the key cap. key = IN_SDL2_ScancodeToQuakeKey(event.key.keysym.scancode); #else key = IN_SDL_KeysymToQuakeKey(event.key.keysym.sym); #endif Key_Event (key, down); #if !defined(USE_SDL2) if (down && (event.key.keysym.unicode & ~0x7F) == 0) Char_Event (event.key.keysym.unicode); #endif break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: if (event.button.button < 1 || event.button.button > sizeof(buttonremap) / sizeof(buttonremap[0])) { Con_Printf ("Ignored event for mouse button %d\n", event.button.button); break; } Key_Event(buttonremap[event.button.button - 1], event.button.state == SDL_PRESSED); break; #if defined(USE_SDL2) case SDL_MOUSEWHEEL: if (event.wheel.y > 0) { Key_Event(K_MWHEELUP, true); Key_Event(K_MWHEELUP, false); } else if (event.wheel.y < 0) { Key_Event(K_MWHEELDOWN, true); Key_Event(K_MWHEELDOWN, false); } break; #endif case SDL_MOUSEMOTION: IN_MouseMove(event.motion.xrel, event.motion.yrel); break; case SDL_QUIT: CL_Disconnect (); Sys_Quit (); break; default: break; } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cmd.h�����������������������������������������������������������������������0000644�0000000�0000000�00000010734�12407762022�014442� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_CMD_H #define _QUAKE_CMD_H // cmd.h -- Command buffer and command execution //=========================================================================== /* Any number of commands can be added in a frame, from several different sources. Most commands come from either keybindings or console line input, but remote servers can also send across commands and entire text files can be execed. The + command line options are also added to the command buffer. The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute (); */ void Cbuf_Init (void); // allocates an initial text buffer that will grow as needed void Cbuf_AddText (const char *text); // as new commands are generated from the console or keybindings, // the text is added to the end of the command buffer. void Cbuf_InsertText (const char *text); // when a command wants to issue other commands immediately, the text is // inserted at the beginning of the buffer, before any remaining unexecuted // commands. void Cbuf_Execute (void); // Pulls off \n terminated lines of text from the command buffer and sends // them through Cmd_ExecuteString. Stops when the buffer is empty. // Normally called once per frame, but may be explicitly invoked. // Do not call inside a command function! //=========================================================================== /* Command execution takes a null terminated string, breaks it into tokens, then searches for a command or variable that matches the first token. Commands can come from three sources, but the handler functions may choose to dissallow the action or forward it to a remote server if the source is not apropriate. */ typedef void (*xcommand_t) (void); typedef enum { src_client, // came in over a net connection as a clc_stringcmd // host_client will be valid during this state. src_command // from the command buffer } cmd_source_t; extern cmd_source_t cmd_source; void Cmd_Init (void); void Cmd_AddCommand (const char *cmd_name, xcommand_t function); // called by the init functions of other parts of the program to // register commands and functions to call for them. // The cmd_name is referenced later, so it should not be in temp memory qboolean Cmd_Exists (const char *cmd_name); // used by the cvar code to check for cvar / command name overlap const char *Cmd_CompleteCommand (const char *partial); // attempts to match a partial command for automatic command line completion // returns NULL if nothing fits int Cmd_Argc (void); const char *Cmd_Argv (int arg); const char *Cmd_Args (void); // The functions that execute commands get their parameters with these // functions. Cmd_Argv () will return an empty string, not a NULL // if arg > argc, so string operations are allways safe. int Cmd_CheckParm (const char *parm); // Returns the position (1 to argc-1) in the command's argument list // where the given parameter apears, or 0 if not present void Cmd_TokenizeString (const char *text); // Takes a null terminated string. Does not need to be /n terminated. // breaks the string up into arg tokens. void Cmd_ExecuteString (const char *text, cmd_source_t src); // Parses a single line of text into arguments and tries to execute it. // The text can come from the command buffer, a remote client, or stdin. void Cmd_ForwardToServer (void); // adds the current command line as a clc_stringcmd to the client message. // things like godmode, noclip, etc, are commands directed to the server, // so when they are typed in at the console, they will need to be forwarded. void Cmd_Print (const char *text); // used by command functions to send output to either the graphics console or // passed as a print message to the client #endif /* _QUAKE_CMD_H */ ������������������������������������quakespasm-0.91.0/Quake/image.h���������������������������������������������������������������������0000644�0000000�0000000�00000002410�12407762022�014751� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __GL_IMAGE_H #define __GL_IMAGE_H //image.h -- image reading / writing //be sure to free the hunk after using these loading functions byte *Image_LoadTGA (FILE *f, int *width, int *height); byte *Image_LoadPCX (FILE *f, int *width, int *height); byte *Image_LoadImage (const char *name, int *width, int *height); qboolean Image_WriteTGA (const char *name, byte *data, int width, int height, int bpp, qboolean upsidedown); #endif /* __GL_IMAGE_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/console.c�������������������������������������������������������������������0000644�0000000�0000000�00000070034�12566313647�015346� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // console.c #include <sys/types.h> #include <time.h> #include <sys/stat.h> #include <fcntl.h> #ifdef _WIN32 #include <io.h> #else #include <unistd.h> #endif #include "quakedef.h" int con_linewidth; float con_cursorspeed = 4; #define CON_TEXTSIZE 65536 //johnfitz -- new default size #define CON_MINSIZE 16384 //johnfitz -- old default, now the minimum size int con_buffersize; //johnfitz -- user can now override default qboolean con_forcedup; // because no entities to refresh int con_totallines; // total lines in console scrollback int con_backscroll; // lines up from bottom to display int con_current; // where next message will be printed int con_x; // offset in current line for next print char *con_text = NULL; cvar_t con_notifytime = {"con_notifytime","3",CVAR_NONE}; //seconds cvar_t con_logcenterprint = {"con_logcenterprint", "1", CVAR_NONE}; //johnfitz char con_lastcenterstring[1024]; //johnfitz #define NUM_CON_TIMES 4 float con_times[NUM_CON_TIMES]; // realtime time the line was generated // for transparent notify lines int con_vislines; qboolean con_debuglog = false; qboolean con_initialized; /* ================ Con_Quakebar -- johnfitz -- returns a bar of the desired length, but never wider than the console includes a newline, unless len >= con_linewidth. ================ */ const char *Con_Quakebar (int len) { static char bar[42]; int i; len = q_min(len, (int)sizeof(bar) - 2); len = q_min(len, con_linewidth); bar[0] = '\35'; for (i = 1; i < len - 1; i++) bar[i] = '\36'; bar[len-1] = '\37'; if (len < con_linewidth) { bar[len] = '\n'; bar[len+1] = 0; } else bar[len] = 0; return bar; } /* ================ Con_ToggleConsole_f ================ */ extern int history_line; //johnfitz void Con_ToggleConsole_f (void) { if (key_dest == key_console/* || (key_dest == key_game && con_forcedup)*/) { key_lines[edit_line][1] = 0; // clear any typing key_linepos = 1; con_backscroll = 0; //johnfitz -- toggleconsole should return you to the bottom of the scrollback history_line = edit_line; //johnfitz -- it should also return you to the bottom of the command history if (cls.state == ca_connected) { IN_Activate(); key_dest = key_game; } else { M_Menu_Main_f (); } } else { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_console; } SCR_EndLoadingPlaque (); memset (con_times, 0, sizeof(con_times)); } /* ================ Con_Clear_f ================ */ static void Con_Clear_f (void) { if (con_text) Q_memset (con_text, ' ', con_buffersize); //johnfitz -- con_buffersize replaces CON_TEXTSIZE con_backscroll = 0; //johnfitz -- if console is empty, being scrolled up is confusing } /* ================ Con_Dump_f -- johnfitz -- adapted from quake2 source ================ */ static void Con_Dump_f (void) { int l, x; const char *line; FILE *f; char buffer[1024]; char name[MAX_OSPATH]; q_snprintf (name, sizeof(name), "%s/condump.txt", com_gamedir); COM_CreatePath (name); f = fopen (name, "w"); if (!f) { Con_Printf ("ERROR: couldn't open file %s.\n", name); return; } // skip initial empty lines for (l = con_current - con_totallines + 1; l <= con_current; l++) { line = con_text + (l % con_totallines)*con_linewidth; for (x = 0; x < con_linewidth; x++) if (line[x] != ' ') break; if (x != con_linewidth) break; } // write the remaining lines buffer[con_linewidth] = 0; for ( ; l <= con_current; l++) { line = con_text + (l%con_totallines)*con_linewidth; strncpy (buffer, line, con_linewidth); for (x = con_linewidth - 1; x >= 0; x--) { if (buffer[x] == ' ') buffer[x] = 0; else break; } for (x = 0; buffer[x]; x++) buffer[x] &= 0x7f; fprintf (f, "%s\n", buffer); } fclose (f); Con_Printf ("Dumped console text to %s.\n", name); } /* ================ Con_ClearNotify ================ */ void Con_ClearNotify (void) { int i; for (i = 0; i < NUM_CON_TIMES; i++) con_times[i] = 0; } /* ================ Con_MessageMode_f ================ */ static void Con_MessageMode_f (void) { if (cls.state != ca_connected || cls.demoplayback) return; chat_team = false; key_dest = key_message; } /* ================ Con_MessageMode2_f ================ */ static void Con_MessageMode2_f (void) { if (cls.state != ca_connected || cls.demoplayback) return; chat_team = true; key_dest = key_message; } /* ================ Con_CheckResize If the line width has changed, reformat the buffer. ================ */ void Con_CheckResize (void) { int i, j, width, oldwidth, oldtotallines, numlines, numchars; char *tbuf; //johnfitz -- tbuf no longer a static array int mark; //johnfitz width = (vid.conwidth >> 3) - 2; //johnfitz -- use vid.conwidth instead of vid.width if (width == con_linewidth) return; oldwidth = con_linewidth; con_linewidth = width; oldtotallines = con_totallines; con_totallines = con_buffersize / con_linewidth; //johnfitz -- con_buffersize replaces CON_TEXTSIZE numlines = oldtotallines; if (con_totallines < numlines) numlines = con_totallines; numchars = oldwidth; if (con_linewidth < numchars) numchars = con_linewidth; mark = Hunk_LowMark (); //johnfitz tbuf = (char *) Hunk_Alloc (con_buffersize); //johnfitz Q_memcpy (tbuf, con_text, con_buffersize);//johnfitz -- con_buffersize replaces CON_TEXTSIZE Q_memset (con_text, ' ', con_buffersize);//johnfitz -- con_buffersize replaces CON_TEXTSIZE for (i = 0; i < numlines; i++) { for (j = 0; j < numchars; j++) { con_text[(con_totallines - 1 - i) * con_linewidth + j] = tbuf[((con_current - i + oldtotallines) % oldtotallines) * oldwidth + j]; } } Hunk_FreeToLowMark (mark); //johnfitz Con_ClearNotify (); con_backscroll = 0; con_current = con_totallines - 1; } /* ================ Con_Init ================ */ void Con_Init (void) { int i; //johnfitz -- user settable console buffer size i = COM_CheckParm("-consize"); if (i && i < com_argc-1) con_buffersize = q_max(CON_MINSIZE,Q_atoi(com_argv[i+1])*1024); else con_buffersize = CON_TEXTSIZE; //johnfitz con_text = (char *) Hunk_AllocName (con_buffersize, "context");//johnfitz -- con_buffersize replaces CON_TEXTSIZE Q_memset (con_text, ' ', con_buffersize);//johnfitz -- con_buffersize replaces CON_TEXTSIZE con_linewidth = -1; //johnfitz -- no need to run Con_CheckResize here con_linewidth = 38; con_totallines = con_buffersize / con_linewidth;//johnfitz -- con_buffersize replaces CON_TEXTSIZE con_backscroll = 0; con_current = con_totallines - 1; //johnfitz Con_Printf ("Console initialized.\n"); Cvar_RegisterVariable (&con_notifytime); Cvar_RegisterVariable (&con_logcenterprint); //johnfitz Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); Cmd_AddCommand ("messagemode", Con_MessageMode_f); Cmd_AddCommand ("messagemode2", Con_MessageMode2_f); Cmd_AddCommand ("clear", Con_Clear_f); Cmd_AddCommand ("condump", Con_Dump_f); //johnfitz con_initialized = true; } /* =============== Con_Linefeed =============== */ static void Con_Linefeed (void) { //johnfitz -- improved scrolling if (con_backscroll) con_backscroll++; if (con_backscroll > con_totallines - (glheight>>3) - 1) con_backscroll = con_totallines - (glheight>>3) - 1; //johnfitz con_x = 0; con_current++; Q_memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth); } /* ================ Con_Print Handles cursor positioning, line wrapping, etc All console printing must go through this in order to be logged to disk If no console is visible, the notify window will pop up. ================ */ static void Con_Print (const char *txt) { int y; int c, l; static int cr; int mask; qboolean boundary; //con_backscroll = 0; //johnfitz -- better console scrolling if (txt[0] == 1) { mask = 128; // go to colored text S_LocalSound ("misc/talk.wav"); // play talk wav txt++; } else if (txt[0] == 2) { mask = 128; // go to colored text txt++; } else mask = 0; boundary = true; while ( (c = *txt) ) { if (c <= ' ') { boundary = true; } else if (boundary) { // count word length for (l = 0; l < con_linewidth; l++) if (txt[l] <= ' ') break; // word wrap if (l != con_linewidth && (con_x + l > con_linewidth)) con_x = 0; boundary = false; } txt++; if (cr) { con_current--; cr = false; } if (!con_x) { Con_Linefeed (); // mark time for transparent overlay if (con_current >= 0) con_times[con_current % NUM_CON_TIMES] = realtime; } switch (c) { case '\n': con_x = 0; break; case '\r': con_x = 0; cr = 1; break; default: // display character and advance y = con_current % con_totallines; con_text[y*con_linewidth+con_x] = c | mask; con_x++; if (con_x >= con_linewidth) con_x = 0; break; } } } // borrowed from uhexen2 by S.A. for new procs, LOG_Init, LOG_Close static char logfilename[MAX_OSPATH]; // current logfile name static int log_fd = -1; // log file descriptor /* ================ Con_DebugLog ================ */ void Con_DebugLog(const char *msg) { if (log_fd == -1) return; write(log_fd, msg, strlen(msg)); } /* ================ Con_Printf Handles cursor positioning, line wrapping, etc ================ */ #define MAXPRINTMSG 4096 void Con_Printf (const char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; static qboolean inupdate; va_start (argptr, fmt); q_vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); // also echo to debugging console Sys_Printf ("%s", msg); // log all messages to file if (con_debuglog) Con_DebugLog(msg); if (!con_initialized) return; if (cls.state == ca_dedicated) return; // no graphics mode // write it to the scrollable buffer Con_Print (msg); // update the screen if the console is displayed if (cls.signon != SIGNONS && !scr_disabled_for_loading ) { // protect against infinite loop if something in SCR_UpdateScreen calls // Con_Printd if (!inupdate) { inupdate = true; SCR_UpdateScreen (); inupdate = false; } } } /* ================ Con_DWarning -- ericw same as Con_Warning, but only prints if "developer" cvar is set. use for "exceeds standard limit of" messages, which are only relevant for developers targetting vanilla engines ================ */ void Con_DWarning (const char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; if (!developer.value) return; // don't confuse non-developers with techie stuff... va_start (argptr, fmt); q_vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); Con_SafePrintf ("\x02Warning: "); Con_Printf ("%s", msg); } /* ================ Con_Warning -- johnfitz -- prints a warning to the console ================ */ void Con_Warning (const char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; va_start (argptr, fmt); q_vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); Con_SafePrintf ("\x02Warning: "); Con_Printf ("%s", msg); } /* ================ Con_DPrintf A Con_Printf that only shows up if the "developer" cvar is set ================ */ void Con_DPrintf (const char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; if (!developer.value) return; // don't confuse non-developers with techie stuff... va_start (argptr, fmt); q_vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); Con_SafePrintf ("%s", msg); //johnfitz -- was Con_Printf } /* ================ Con_DPrintf2 -- johnfitz -- only prints if "developer" >= 2 currently not used ================ */ void Con_DPrintf2 (const char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; if (developer.value >= 2) { va_start (argptr, fmt); q_vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); Con_Printf ("%s", msg); } } /* ================== Con_SafePrintf Okay to call even when the screen can't be updated ================== */ void Con_SafePrintf (const char *fmt, ...) { va_list argptr; char msg[1024]; int temp; va_start (argptr, fmt); q_vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); temp = scr_disabled_for_loading; scr_disabled_for_loading = true; Con_Printf ("%s", msg); scr_disabled_for_loading = temp; } /* ================ Con_CenterPrintf -- johnfitz -- pad each line with spaces to make it appear centered ================ */ void Con_CenterPrintf (int linewidth, const char *fmt, ...) __attribute__((__format__(__printf__,2,3))); void Con_CenterPrintf (int linewidth, const char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; //the original message char line[MAXPRINTMSG]; //one line from the message char spaces[21]; //buffer for spaces char *src, *dst; int len, s; va_start (argptr, fmt); q_vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); linewidth = q_min(linewidth, con_linewidth); for (src = msg; *src; ) { dst = line; while (*src && *src != '\n') *dst++ = *src++; *dst = 0; if (*src == '\n') src++; len = strlen(line); if (len < linewidth) { s = (linewidth-len)/2; memset (spaces, ' ', s); spaces[s] = 0; Con_Printf ("%s%s\n", spaces, line); } else Con_Printf ("%s\n", line); } } /* ================== Con_LogCenterPrint -- johnfitz -- echo centerprint message to the console ================== */ void Con_LogCenterPrint (const char *str) { if (!strcmp(str, con_lastcenterstring)) return; //ignore duplicates if (cl.gametype == GAME_DEATHMATCH && con_logcenterprint.value != 2) return; //don't log in deathmatch strcpy(con_lastcenterstring, str); if (con_logcenterprint.value) { Con_Printf ("%s", Con_Quakebar(40)); Con_CenterPrintf (40, "%s\n", str); Con_Printf ("%s", Con_Quakebar(40)); Con_ClearNotify (); } } /* ============================================================================== TAB COMPLETION ============================================================================== */ //johnfitz -- tab completion stuff //unique defs char key_tabpartial[MAXCMDLINE]; typedef struct tab_s { const char *name; const char *type; struct tab_s *next; struct tab_s *prev; } tab_t; tab_t *tablist; //defs from elsewhere extern qboolean keydown[256]; typedef struct cmd_function_s { struct cmd_function_s *next; const char *name; xcommand_t function; } cmd_function_t; extern cmd_function_t *cmd_functions; #define MAX_ALIAS_NAME 32 typedef struct cmdalias_s { struct cmdalias_s *next; char name[MAX_ALIAS_NAME]; char *value; } cmdalias_t; extern cmdalias_t *cmd_alias; /* ============ AddToTabList -- johnfitz tablist is a doubly-linked loop, alphabetized by name ============ */ // bash_partial is the string that can be expanded, // aka Linux Bash shell. -- S.A. static char bash_partial[80]; static qboolean bash_singlematch; void AddToTabList (const char *name, const char *type) { tab_t *t,*insert; char *i_bash; const char *i_name; if (!*bash_partial) { strncpy (bash_partial, name, 79); bash_partial[79] = '\0'; } else { bash_singlematch = 0; // find max common between bash_partial and name i_bash = bash_partial; i_name = name; while (*i_bash && (*i_bash == *i_name)) { i_bash++; i_name++; } *i_bash = 0; } t = (tab_t *) Hunk_Alloc(sizeof(tab_t)); t->name = name; t->type = type; if (!tablist) //create list { tablist = t; t->next = t; t->prev = t; } else if (strcmp(name, tablist->name) < 0) //insert at front { t->next = tablist; t->prev = tablist->prev; t->next->prev = t; t->prev->next = t; tablist = t; } else //insert later { insert = tablist; do { if (strcmp(name, insert->name) < 0) break; insert = insert->next; } while (insert != tablist); t->next = insert; t->prev = insert->prev; t->next->prev = t; t->prev->next = t; } } // This is redefined from host_cmd.c typedef struct filelist_item_s { char name[32]; struct filelist_item_s *next; } filelist_item_t; extern filelist_item_t *extralevels; extern filelist_item_t *modlist; extern filelist_item_t *demolist; typedef struct arg_completion_type_s { const char *command; filelist_item_t **filelist; } arg_completion_type_t; static const arg_completion_type_t arg_completion_types[] = { { "map ", &extralevels }, { "changelevel ", &extralevels }, { "game ", &modlist }, { "record ", &demolist }, { "playdemo ", &demolist } }; static const int num_arg_completion_types = sizeof(arg_completion_types)/sizeof(arg_completion_types[0]); /* ============ FindCompletion -- stevenaaus ============ */ const char *FindCompletion (const char *partial, filelist_item_t *filelist, int *nummatches_out) { static char matched[32]; char *i_matched, *i_name; filelist_item_t *file; int init, match, plen; memset(matched, 0, sizeof(matched)); plen = strlen(partial); match = 0; for (file = filelist, init = 0; file; file = file->next) { if (!strncmp(file->name, partial, plen)) { if (init == 0) { init = 1; strncpy (matched, file->name, sizeof(matched)-1); matched[sizeof(matched)-1] = '\0'; } else { // find max common i_matched = matched; i_name = file->name; while (*i_matched && (*i_matched == *i_name)) { i_matched++; i_name++; } *i_matched = 0; } match++; } } *nummatches_out = match; if (match > 1) { for (file = filelist; file; file = file->next) { if (!strncmp(file->name, partial, plen)) Con_SafePrintf (" %s\n", file->name); } Con_SafePrintf ("\n"); } return matched; } /* ============ BuildTabList -- johnfitz ============ */ void BuildTabList (const char *partial) { cmdalias_t *alias; cvar_t *cvar; cmd_function_t *cmd; int len; tablist = NULL; len = strlen(partial); bash_partial[0] = 0; bash_singlematch = 1; cvar = Cvar_FindVarAfter ("", CVAR_NONE); for ( ; cvar ; cvar=cvar->next) if (!Q_strncmp (partial, cvar->name, len)) AddToTabList (cvar->name, "cvar"); for (cmd=cmd_functions ; cmd ; cmd=cmd->next) if (!Q_strncmp (partial,cmd->name, len)) AddToTabList (cmd->name, "command"); for (alias=cmd_alias ; alias ; alias=alias->next) if (!Q_strncmp (partial, alias->name, len)) AddToTabList (alias->name, "alias"); } /* ============ Con_TabComplete -- johnfitz ============ */ void Con_TabComplete (void) { char partial[MAXCMDLINE]; const char *match; static char *c; tab_t *t; int mark, i; // if editline is empty, return if (key_lines[edit_line][1] == 0) return; // get partial string (space -> cursor) if (!key_tabpartial[0]) //first time through, find new insert point. (Otherwise, use previous.) { //work back from cursor until you find a space, quote, semicolon, or prompt c = key_lines[edit_line] + key_linepos - 1; //start one space left of cursor while (*c!=' ' && *c!='\"' && *c!=';' && c!=key_lines[edit_line]) c--; c++; //start 1 char after the separator we just found } for (i = 0; c + i < key_lines[edit_line] + key_linepos; i++) partial[i] = c[i]; partial[i] = 0; // Map autocomplete function -- S.A // Since we don't have argument completion, this hack will do for now... for (i=0; i<num_arg_completion_types; i++) { // arg_completion contains a command we can complete the arguments // for (like "map ") and a list of all the maps. arg_completion_type_t arg_completion = arg_completion_types[i]; const char *command_name = arg_completion.command; if (!strncmp (key_lines[edit_line] + 1, command_name, strlen(command_name))) { int nummatches = 0; const char *matched_map = FindCompletion(partial, *arg_completion.filelist, &nummatches); if (!*matched_map) return; q_strlcpy (partial, matched_map, MAXCMDLINE); *c = '\0'; q_strlcat (key_lines[edit_line], partial, MAXCMDLINE); key_linepos = c - key_lines[edit_line] + Q_strlen(matched_map); //set new cursor position if (key_linepos >= MAXCMDLINE) key_linepos = MAXCMDLINE - 1; // if only one match, append a space if (key_linepos < MAXCMDLINE - 1 && key_lines[edit_line][key_linepos] == 0 && (nummatches == 1)) { key_lines[edit_line][key_linepos] = ' '; key_linepos++; key_lines[edit_line][key_linepos] = 0; } c = key_lines[edit_line] + key_linepos; return; } } //if partial is empty, return if (partial[0] == 0) return; //trim trailing space becuase it screws up string comparisons if (i > 0 && partial[i-1] == ' ') partial[i-1] = 0; // find a match mark = Hunk_LowMark(); if (!key_tabpartial[0]) //first time through { q_strlcpy (key_tabpartial, partial, MAXCMDLINE); BuildTabList (key_tabpartial); if (!tablist) return; // print list if length > 1 if (tablist->next != tablist) { t = tablist; Con_SafePrintf("\n"); do { Con_SafePrintf(" %s (%s)\n", t->name, t->type); t = t->next; } while (t != tablist); Con_SafePrintf("\n"); } // match = tablist->name; // First time, just show maximum matching chars -- S.A. match = bash_partial; } else { BuildTabList (key_tabpartial); if (!tablist) return; //find current match -- can't save a pointer because the list will be rebuilt each time t = tablist; match = keydown[K_SHIFT] ? t->prev->name : t->name; do { if (!Q_strcmp(t->name, partial)) { match = keydown[K_SHIFT] ? t->prev->name : t->next->name; break; } t = t->next; } while (t != tablist); } Hunk_FreeToLowMark(mark); //it's okay to free it here because match is a pointer to persistent data // insert new match into edit line q_strlcpy (partial, match, MAXCMDLINE); //first copy match string q_strlcat (partial, key_lines[edit_line] + key_linepos, MAXCMDLINE); //then add chars after cursor *c = '\0'; //now copy all of this into edit line q_strlcat (key_lines[edit_line], partial, MAXCMDLINE); key_linepos = c - key_lines[edit_line] + Q_strlen(match); //set new cursor position if (key_linepos >= MAXCMDLINE) key_linepos = MAXCMDLINE - 1; // if cursor is at end of string, let's append a space to make life easier if (key_linepos < MAXCMDLINE - 1 && key_lines[edit_line][key_linepos] == 0 && bash_singlematch) { key_lines[edit_line][key_linepos] = ' '; key_linepos++; key_lines[edit_line][key_linepos] = 0; // S.A.: the map argument completion (may be in combination with the bash-style // display behavior changes, causes weirdness when completing the arguments for // the changelevel command. the line below "fixes" it, although I'm not sure about // the reason, yet, neither do I know any possible side effects of it: c = key_lines[edit_line] + key_linepos; } } /* ============================================================================== DRAWING ============================================================================== */ /* ================ Con_DrawNotify Draws the last few lines of output transparently over the game top ================ */ void Con_DrawNotify (void) { int i, x, v; const char *text; float time; GL_SetCanvas (CANVAS_CONSOLE); //johnfitz v = vid.conheight; //johnfitz for (i = con_current-NUM_CON_TIMES+1; i <= con_current; i++) { if (i < 0) continue; time = con_times[i % NUM_CON_TIMES]; if (time == 0) continue; time = realtime - time; if (time > con_notifytime.value) continue; text = con_text + (i % con_totallines)*con_linewidth; clearnotify = 0; for (x = 0; x < con_linewidth; x++) Draw_Character ((x+1)<<3, v, text[x]); v += 8; scr_tileclear_updates = 0; //johnfitz } if (key_dest == key_message) { clearnotify = 0; if (chat_team) { Draw_String (8, v, "say_team:"); x = 11; } else { Draw_String (8, v, "say:"); x = 6; } text = Key_GetChatBuffer(); i = Key_GetChatMsgLen(); if (i > con_linewidth - x - 1) text += i - con_linewidth + x + 1; while (*text) { Draw_Character (x<<3, v, *text); x++; text++; } Draw_Character (x<<3, v, 10 + ((int)(realtime*con_cursorspeed)&1)); v += 8; scr_tileclear_updates = 0; //johnfitz } } /* ================ Con_DrawInput -- johnfitz -- modified to allow insert editing The input line scrolls horizontally if typing goes beyond the right edge ================ */ extern qpic_t *pic_ovr, *pic_ins; //johnfitz -- new cursor handling void Con_DrawInput (void) { int i, ofs; if (key_dest != key_console && !con_forcedup) return; // don't draw anything // prestep if horizontally scrolling if (key_linepos >= con_linewidth) ofs = 1 + key_linepos - con_linewidth; else ofs = 0; // draw input string for (i = 0; key_lines[edit_line][i+ofs] && i < con_linewidth; i++) Draw_Character ((i+1)<<3, vid.conheight - 16, key_lines[edit_line][i+ofs]); // johnfitz -- new cursor handling if (!((int)((realtime-key_blinktime)*con_cursorspeed) & 1)) { i = key_linepos - ofs; Draw_Pic ((i+1)<<3, vid.conheight - 16, key_insert ? pic_ins : pic_ovr); } } /* ================ Con_DrawConsole -- johnfitz -- heavy revision Draws the console with the solid background The typing input line at the bottom should only be drawn if typing is allowed ================ */ void Con_DrawConsole (int lines, qboolean drawinput) { int i, x, y, j, sb, rows; const char *text; char ver[32]; if (lines <= 0) return; con_vislines = lines * vid.conheight / glheight; GL_SetCanvas (CANVAS_CONSOLE); // draw the background Draw_ConsoleBackground (); // draw the buffer text rows = (con_vislines +7)/8; y = vid.conheight - rows*8; rows -= 2; //for input and version lines sb = (con_backscroll) ? 2 : 0; for (i = con_current - rows + 1; i <= con_current - sb; i++, y += 8) { j = i - con_backscroll; if (j < 0) j = 0; text = con_text + (j % con_totallines)*con_linewidth; for (x = 0; x < con_linewidth; x++) Draw_Character ( (x + 1)<<3, y, text[x]); } // draw scrollback arrows if (con_backscroll) { y += 8; // blank line for (x = 0; x < con_linewidth; x += 4) Draw_Character ((x + 1)<<3, y, '^'); y += 8; } // draw the input prompt, user text, and cursor if (drawinput) Con_DrawInput (); //draw version number in bottom right y += 8; sprintf (ver, "QuakeSpasm %1.2f.%d", (float)QUAKESPASM_VERSION, QUAKESPASM_VER_PATCH); for (x = 0; x < (int)strlen(ver); x++) Draw_Character ((con_linewidth - strlen(ver) + x + 2)<<3, y, ver[x] /*+ 128*/); } /* ================== Con_NotifyBox ================== */ void Con_NotifyBox (const char *text) { double t1, t2; int lastkey, lastchar; // during startup for sound / cd warnings Con_Printf ("\n\n%s", Con_Quakebar(40)); //johnfitz Con_Printf ("%s", text); Con_Printf ("Press a key.\n"); Con_Printf ("%s", Con_Quakebar(40)); //johnfitz IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_console; Key_BeginInputGrab (); do { t1 = Sys_DoubleTime (); SCR_UpdateScreen (); Sys_SendKeyEvents (); Key_GetGrabbedInput (&lastkey, &lastchar); Sys_Sleep (16); t2 = Sys_DoubleTime (); realtime += t2-t1; // make the cursor blink } while (lastkey == -1 && lastchar == -1); Key_EndInputGrab (); Con_Printf ("\n"); IN_Activate(); key_dest = key_game; realtime = 0; // put the cursor back to invisible } void LOG_Init (quakeparms_t *parms) { time_t inittime; char session[24]; if (!COM_CheckParm("-condebug")) return; inittime = time (NULL); strftime (session, sizeof(session), "%m/%d/%Y %H:%M:%S", localtime(&inittime)); q_snprintf (logfilename, sizeof(logfilename), "%s/qconsole.log", parms->basedir); // unlink (logfilename); log_fd = open (logfilename, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (log_fd == -1) { fprintf (stderr, "Error: Unable to create log file %s\n", logfilename); return; } con_debuglog = true; Con_DebugLog (va("LOG started on: %s \n", session)); } void LOG_Close (void) { if (log_fd == -1) return; close (log_fd); log_fd = -1; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_codeci.h����������������������������������������������������������������0000644�0000000�0000000�00000003550�12220541170�015757� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Audio Codecs: Adapted from ioquake3 with changes. * For now, only handles streaming music, not sound effects. * * Copyright (C) 1999-2005 Id Software, Inc. * Copyright (C) 2005 Stuart Dalton <badcdev@gmail.com> * Copyright (C) 2010-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #ifndef _SND_CODECI_H_ #define _SND_CODECI_H_ /* Codec internals */ typedef qboolean (*CODEC_INIT)(void); typedef void (*CODEC_SHUTDOWN)(void); typedef qboolean (*CODEC_OPEN)(snd_stream_t *stream); typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer); typedef int (*CODEC_REWIND)(snd_stream_t *stream); typedef void (*CODEC_CLOSE)(snd_stream_t *stream); struct snd_codec_s { unsigned int type; /* handled data type. (1U << n) */ qboolean initialized; /* init succeedded */ const char *ext; /* expected extension */ CODEC_INIT initialize; CODEC_SHUTDOWN shutdown; CODEC_OPEN codec_open; CODEC_READ codec_read; CODEC_REWIND codec_rewind; CODEC_CLOSE codec_close; snd_codec_t *next; }; qboolean S_CodecForwardStream (snd_stream_t *stream, unsigned int type); /* Forward a stream to another codec of 'type' type. */ #endif /* _SND_CODECI_H_ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/mathlib.c�������������������������������������������������������������������0000644�0000000�0000000�00000026437�12407762022�015321� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // mathlib.c -- math primitives #include "quakedef.h" vec3_t vec3_origin = {0,0,0}; /*-----------------------------------------------------------------*/ //#define DEG2RAD( a ) ( a * M_PI ) / 180.0F #define DEG2RAD( a ) ( (a) * M_PI_DIV_180 ) //johnfitz void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) { float d; vec3_t n; float inv_denom; inv_denom = 1.0F / DotProduct( normal, normal ); d = DotProduct( normal, p ) * inv_denom; n[0] = normal[0] * inv_denom; n[1] = normal[1] * inv_denom; n[2] = normal[2] * inv_denom; dst[0] = p[0] - d * n[0]; dst[1] = p[1] - d * n[1]; dst[2] = p[2] - d * n[2]; } /* ** assumes "src" is normalized */ void PerpendicularVector( vec3_t dst, const vec3_t src ) { int pos; int i; float minelem = 1.0F; vec3_t tempvec; /* ** find the smallest magnitude axially aligned vector */ for ( pos = 0, i = 0; i < 3; i++ ) { if ( fabs( src[i] ) < minelem ) { pos = i; minelem = fabs( src[i] ); } } tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; tempvec[pos] = 1.0F; /* ** project the point onto the plane defined by src */ ProjectPointOnPlane( dst, tempvec, src ); /* ** normalize the result */ VectorNormalize( dst ); } //johnfitz -- removed RotatePointAroundVector() becuase it's no longer used and my compiler fucked it up anyway /*-----------------------------------------------------------------*/ float anglemod(float a) { #if 0 if (a >= 0) a -= 360*(int)(a/360); else a += 360*( 1 + (int)(-a/360) ); #endif a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); return a; } /* ================== BOPS_Error Split out like this for ASM to call. ================== */ void BOPS_Error (void) __attribute__((__noreturn__)); void BOPS_Error (void) { Sys_Error ("BoxOnPlaneSide: Bad signbits"); } /* ================== BoxOnPlaneSide Returns 1, 2, or 1 + 2 ================== */ int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p) { float dist1, dist2; int sides; #if 0 // this is done by the BOX_ON_PLANE_SIDE macro before calling this // function // fast axial cases if (p->type < 3) { if (p->dist <= emins[p->type]) return 1; if (p->dist >= emaxs[p->type]) return 2; return 3; } #endif // general case switch (p->signbits) { case 0: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; break; case 1: dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; break; case 2: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; break; case 3: dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; break; case 4: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; break; case 5: dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; break; case 6: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; break; case 7: dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; break; default: dist1 = dist2 = 0; // shut up compiler BOPS_Error (); break; } #if 0 int i; vec3_t corners[2]; for (i=0 ; i<3 ; i++) { if (plane->normal[i] < 0) { corners[0][i] = emins[i]; corners[1][i] = emaxs[i]; } else { corners[1][i] = emins[i]; corners[0][i] = emaxs[i]; } } dist = DotProduct (plane->normal, corners[0]) - plane->dist; dist2 = DotProduct (plane->normal, corners[1]) - plane->dist; sides = 0; if (dist1 >= 0) sides = 1; if (dist2 < 0) sides |= 2; #endif sides = 0; if (dist1 >= p->dist) sides = 1; if (dist2 < p->dist) sides |= 2; #ifdef PARANOID if (sides == 0) Sys_Error ("BoxOnPlaneSide: sides==0"); #endif return sides; } //johnfitz -- the opposite of AngleVectors. this takes forward and generates pitch yaw roll //TODO: take right and up vectors to properly set yaw and roll void VectorAngles (const vec3_t forward, vec3_t angles) { vec3_t temp; temp[0] = forward[0]; temp[1] = forward[1]; temp[2] = 0; angles[PITCH] = -atan2(forward[2], VectorLength(temp)) / M_PI_DIV_180; angles[YAW] = atan2(forward[1], forward[0]) / M_PI_DIV_180; angles[ROLL] = 0; } void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) { float angle; float sr, sp, sy, cr, cp, cy; angle = angles[YAW] * (M_PI*2 / 360); sy = sin(angle); cy = cos(angle); angle = angles[PITCH] * (M_PI*2 / 360); sp = sin(angle); cp = cos(angle); angle = angles[ROLL] * (M_PI*2 / 360); sr = sin(angle); cr = cos(angle); forward[0] = cp*cy; forward[1] = cp*sy; forward[2] = -sp; right[0] = (-1*sr*sp*cy+-1*cr*-sy); right[1] = (-1*sr*sp*sy+-1*cr*cy); right[2] = -1*sr*cp; up[0] = (cr*sp*cy+-sr*-sy); up[1] = (cr*sp*sy+-sr*cy); up[2] = cr*cp; } int VectorCompare (vec3_t v1, vec3_t v2) { int i; for (i=0 ; i<3 ; i++) if (v1[i] != v2[i]) return 0; return 1; } void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc) { vecc[0] = veca[0] + scale*vecb[0]; vecc[1] = veca[1] + scale*vecb[1]; vecc[2] = veca[2] + scale*vecb[2]; } vec_t _DotProduct (vec3_t v1, vec3_t v2) { return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; } void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) { out[0] = veca[0]-vecb[0]; out[1] = veca[1]-vecb[1]; out[2] = veca[2]-vecb[2]; } void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out) { out[0] = veca[0]+vecb[0]; out[1] = veca[1]+vecb[1]; out[2] = veca[2]+vecb[2]; } void _VectorCopy (vec3_t in, vec3_t out) { out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; } void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) { cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; } vec_t VectorLength(vec3_t v) { return sqrt(DotProduct(v,v)); } float VectorNormalize (vec3_t v) { float length, ilength; length = sqrt(DotProduct(v,v)); if (length) { ilength = 1/length; v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; } return length; } void VectorInverse (vec3_t v) { v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; } void VectorScale (vec3_t in, vec_t scale, vec3_t out) { out[0] = in[0]*scale; out[1] = in[1]*scale; out[2] = in[2]*scale; } int Q_log2(int val) { int answer=0; while (val>>=1) answer++; return answer; } /* ================ R_ConcatRotations ================ */ void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]) { out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; } /* ================ R_ConcatTransforms ================ */ void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) { out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3]; out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3]; out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; } /* =================== FloorDivMod Returns mathematically correct (floor-based) quotient and remainder for numer and denom, both of which should contain no fractional part. The quotient must fit in 32 bits. ==================== */ void FloorDivMod (double numer, double denom, int *quotient, int *rem) { int q, r; double x; #ifndef PARANOID if (denom <= 0.0) Sys_Error ("FloorDivMod: bad denominator %f\n", denom); // if ((floor(numer) != numer) || (floor(denom) != denom)) // Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n", // numer, denom); #endif if (numer >= 0.0) { x = floor(numer / denom); q = (int)x; r = (int)floor(numer - (x * denom)); } else { // // perform operations with positive values, and fix mod to make floor-based // x = floor(-numer / denom); q = -(int)x; r = (int)floor(-numer - (x * denom)); if (r != 0) { q--; r = (int)denom - r; } } *quotient = q; *rem = r; } /* =================== GreatestCommonDivisor ==================== */ int GreatestCommonDivisor (int i1, int i2) { if (i1 > i2) { if (i2 == 0) return (i1); return GreatestCommonDivisor (i2, i1 % i2); } else { if (i1 == 0) return (i2); return GreatestCommonDivisor (i1, i2 % i1); } } /* =================== Invert24To16 Inverts an 8.24 value to a 16.16 value ==================== */ fixed16_t Invert24To16(fixed16_t val) { if (val < 256) return (0xFFFFFFFF); return (fixed16_t) (((double)0x10000 * (double)0x1000000 / (double)val) + 0.5); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_modplug.h���������������������������������������������������������������0000644�0000000�0000000�00000000361�12220541170�016175� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* module tracker decoding support using libmodplug */ #if !defined(_SND_MODPLUG_H_) #define _SND_MODPLUG_H_ #if defined(USE_CODEC_MODPLUG) extern snd_codec_t modplug_codec; #endif /* USE_CODEC_MODPLUG */ #endif /* ! _SND_MODPLUG_H_ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/pr_edict.c������������������������������������������������������������������0000644�0000000�0000000�00000064637�12530514531�015473� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_edict.c -- entity dictionary #include "quakedef.h" dprograms_t *progs; dfunction_t *pr_functions; static char *pr_strings; static int pr_stringssize; static const char **pr_knownstrings; static int pr_maxknownstrings; static int pr_numknownstrings; static ddef_t *pr_fielddefs; static ddef_t *pr_globaldefs; qboolean pr_alpha_supported; //johnfitz dstatement_t *pr_statements; globalvars_t *pr_global_struct; float *pr_globals; // same as pr_global_struct int pr_edict_size; // in bytes unsigned short pr_crc; int type_size[8] = { 1, // ev_void 1, // sizeof(string_t) / 4 // ev_string 1, // ev_float 3, // ev_vector 1, // ev_entity 1, // ev_field 1, // sizeof(func_t) / 4 // ev_function 1 // sizeof(void *) / 4 // ev_pointer }; static ddef_t *ED_FieldAtOfs (int ofs); static qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s); #define MAX_FIELD_LEN 64 #define GEFV_CACHESIZE 2 typedef struct { ddef_t *pcache; char field[MAX_FIELD_LEN]; } gefv_cache; static gefv_cache gefvCache[GEFV_CACHESIZE] = { { NULL, "" }, { NULL, "" } }; cvar_t nomonsters = {"nomonsters", "0", CVAR_NONE}; cvar_t gamecfg = {"gamecfg", "0", CVAR_NONE}; cvar_t scratch1 = {"scratch1", "0", CVAR_NONE}; cvar_t scratch2 = {"scratch2", "0", CVAR_NONE}; cvar_t scratch3 = {"scratch3", "0", CVAR_NONE}; cvar_t scratch4 = {"scratch4", "0", CVAR_NONE}; cvar_t savedgamecfg = {"savedgamecfg", "0", CVAR_ARCHIVE}; cvar_t saved1 = {"saved1", "0", CVAR_ARCHIVE}; cvar_t saved2 = {"saved2", "0", CVAR_ARCHIVE}; cvar_t saved3 = {"saved3", "0", CVAR_ARCHIVE}; cvar_t saved4 = {"saved4", "0", CVAR_ARCHIVE}; /* ================= ED_ClearEdict Sets everything to NULL ================= */ void ED_ClearEdict (edict_t *e) { memset (&e->v, 0, progs->entityfields * 4); e->free = false; } /* ================= ED_Alloc Either finds a free edict, or allocates a new one. Try to avoid reusing an entity that was recently freed, because it can cause the client to think the entity morphed into something else instead of being removed and recreated, which can cause interpolated angles and bad trails. ================= */ edict_t *ED_Alloc (void) { int i; edict_t *e; for (i = svs.maxclients + 1; i < sv.num_edicts; i++) { e = EDICT_NUM(i); // the first couple seconds of server time can involve a lot of // freeing and allocating, so relax the replacement policy if (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) ) { ED_ClearEdict (e); return e; } } if (i == sv.max_edicts) //johnfitz -- use sv.max_edicts instead of MAX_EDICTS Host_Error ("ED_Alloc: no free edicts (max_edicts is %i)", sv.max_edicts); sv.num_edicts++; e = EDICT_NUM(i); ED_ClearEdict (e); return e; } /* ================= ED_Free Marks the edict as free FIXME: walk all entities and NULL out references to this entity ================= */ void ED_Free (edict_t *ed) { SV_UnlinkEdict (ed); // unlink from world bsp ed->free = true; ed->v.model = 0; ed->v.takedamage = 0; ed->v.modelindex = 0; ed->v.colormap = 0; ed->v.skin = 0; ed->v.frame = 0; VectorCopy (vec3_origin, ed->v.origin); VectorCopy (vec3_origin, ed->v.angles); ed->v.nextthink = -1; ed->v.solid = 0; ed->alpha = ENTALPHA_DEFAULT; //johnfitz -- reset alpha for next entity ed->freetime = sv.time; } //=========================================================================== /* ============ ED_GlobalAtOfs ============ */ static ddef_t *ED_GlobalAtOfs (int ofs) { ddef_t *def; int i; for (i = 0; i < progs->numglobaldefs; i++) { def = &pr_globaldefs[i]; if (def->ofs == ofs) return def; } return NULL; } /* ============ ED_FieldAtOfs ============ */ static ddef_t *ED_FieldAtOfs (int ofs) { ddef_t *def; int i; for (i = 0; i < progs->numfielddefs; i++) { def = &pr_fielddefs[i]; if (def->ofs == ofs) return def; } return NULL; } /* ============ ED_FindField ============ */ static ddef_t *ED_FindField (const char *name) { ddef_t *def; int i; for (i = 0; i < progs->numfielddefs; i++) { def = &pr_fielddefs[i]; if ( !strcmp(PR_GetString(def->s_name), name) ) return def; } return NULL; } /* ============ ED_FindGlobal ============ */ static ddef_t *ED_FindGlobal (const char *name) { ddef_t *def; int i; for (i = 0; i < progs->numglobaldefs; i++) { def = &pr_globaldefs[i]; if ( !strcmp(PR_GetString(def->s_name), name) ) return def; } return NULL; } /* ============ ED_FindFunction ============ */ static dfunction_t *ED_FindFunction (const char *fn_name) { dfunction_t *func; int i; for (i = 0; i < progs->numfunctions; i++) { func = &pr_functions[i]; if ( !strcmp(PR_GetString(func->s_name), fn_name) ) return func; } return NULL; } /* ============ GetEdictFieldValue ============ */ eval_t *GetEdictFieldValue(edict_t *ed, const char *field) { ddef_t *def = NULL; int i; static int rep = 0; for (i = 0; i < GEFV_CACHESIZE; i++) { if (!strcmp(field, gefvCache[i].field)) { def = gefvCache[i].pcache; goto Done; } } def = ED_FindField (field); if (strlen(field) < MAX_FIELD_LEN) { gefvCache[rep].pcache = def; strcpy (gefvCache[rep].field, field); rep ^= 1; } Done: if (!def) return NULL; return (eval_t *)((char *)&ed->v + def->ofs*4); } /* ============ PR_ValueString (etype_t type, eval_t *val) Returns a string describing *data in a type specific manner ============= */ static const char *PR_ValueString (int type, eval_t *val) { static char line[512]; ddef_t *def; dfunction_t *f; type &= ~DEF_SAVEGLOBAL; switch (type) { case ev_string: sprintf (line, "%s", PR_GetString(val->string)); break; case ev_entity: sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) ); break; case ev_function: f = pr_functions + val->function; sprintf (line, "%s()", PR_GetString(f->s_name)); break; case ev_field: def = ED_FieldAtOfs ( val->_int ); sprintf (line, ".%s", PR_GetString(def->s_name)); break; case ev_void: sprintf (line, "void"); break; case ev_float: sprintf (line, "%5.1f", val->_float); break; case ev_vector: sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]); break; case ev_pointer: sprintf (line, "pointer"); break; default: sprintf (line, "bad type %i", type); break; } return line; } /* ============ PR_UglyValueString (etype_t type, eval_t *val) Returns a string describing *data in a type specific manner Easier to parse than PR_ValueString ============= */ static const char *PR_UglyValueString (int type, eval_t *val) { static char line[512]; ddef_t *def; dfunction_t *f; type &= ~DEF_SAVEGLOBAL; switch (type) { case ev_string: sprintf (line, "%s", PR_GetString(val->string)); break; case ev_entity: sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict))); break; case ev_function: f = pr_functions + val->function; sprintf (line, "%s", PR_GetString(f->s_name)); break; case ev_field: def = ED_FieldAtOfs ( val->_int ); sprintf (line, "%s", PR_GetString(def->s_name)); break; case ev_void: sprintf (line, "void"); break; case ev_float: sprintf (line, "%f", val->_float); break; case ev_vector: sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); break; default: sprintf (line, "bad type %i", type); break; } return line; } /* ============ PR_GlobalString Returns a string with a description and the contents of a global, padded to 20 field width ============ */ const char *PR_GlobalString (int ofs) { static char line[512]; const char *s; int i; ddef_t *def; void *val; val = (void *)&pr_globals[ofs]; def = ED_GlobalAtOfs(ofs); if (!def) sprintf (line,"%i(?)", ofs); else { s = PR_ValueString (def->type, (eval_t *)val); sprintf (line,"%i(%s)%s", ofs, PR_GetString(def->s_name), s); } i = strlen(line); for ( ; i < 20; i++) strcat (line, " "); strcat (line, " "); return line; } const char *PR_GlobalStringNoContents (int ofs) { static char line[512]; int i; ddef_t *def; def = ED_GlobalAtOfs(ofs); if (!def) sprintf (line,"%i(?)", ofs); else sprintf (line,"%i(%s)", ofs, PR_GetString(def->s_name)); i = strlen(line); for ( ; i < 20; i++) strcat (line, " "); strcat (line, " "); return line; } /* ============= ED_Print For debugging ============= */ void ED_Print (edict_t *ed) { ddef_t *d; int *v; int i, j, l; const char *name; int type; if (ed->free) { Con_Printf ("FREE\n"); return; } Con_SafePrintf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); //johnfitz -- was Con_Printf for (i = 1; i < progs->numfielddefs; i++) { d = &pr_fielddefs[i]; name = PR_GetString(d->s_name); l = strlen (name); if (l > 1 && name[l - 2] == '_') continue; // skip _x, _y, _z vars v = (int *)((char *)&ed->v + d->ofs*4); // if the value is still all 0, skip the field type = d->type & ~DEF_SAVEGLOBAL; for (j = 0; j < type_size[type]; j++) { if (v[j]) break; } if (j == type_size[type]) continue; Con_SafePrintf ("%s", name); //johnfitz -- was Con_Printf while (l++ < 15) Con_SafePrintf (" "); //johnfitz -- was Con_Printf Con_SafePrintf ("%s\n", PR_ValueString(d->type, (eval_t *)v)); //johnfitz -- was Con_Printf } } /* ============= ED_Write For savegames ============= */ void ED_Write (FILE *f, edict_t *ed) { ddef_t *d; int *v; int i, j; const char *name; int type; fprintf (f, "{\n"); if (ed->free) { fprintf (f, "}\n"); return; } for (i = 1; i < progs->numfielddefs; i++) { d = &pr_fielddefs[i]; name = PR_GetString(d->s_name); j = strlen (name); if (j > 1 && name[j - 2] == '_') continue; // skip _x, _y, _z vars v = (int *)((char *)&ed->v + d->ofs*4); // if the value is still all 0, skip the field type = d->type & ~DEF_SAVEGLOBAL; for (j = 0; j < type_size[type]; j++) { if (v[j]) break; } if (j == type_size[type]) continue; fprintf (f, "\"%s\" ", name); fprintf (f, "\"%s\"\n", PR_UglyValueString(d->type, (eval_t *)v)); } //johnfitz -- save entity alpha manually when progs.dat doesn't know about alpha if (!pr_alpha_supported && ed->alpha != ENTALPHA_DEFAULT) fprintf (f, "\"alpha\" \"%f\"\n", ENTALPHA_TOSAVE(ed->alpha)); //johnfitz fprintf (f, "}\n"); } void ED_PrintNum (int ent) { ED_Print (EDICT_NUM(ent)); } /* ============= ED_PrintEdicts For debugging, prints all the entities in the current server ============= */ void ED_PrintEdicts (void) { int i; if (!sv.active) return; Con_Printf ("%i entities\n", sv.num_edicts); for (i = 0; i < sv.num_edicts; i++) ED_PrintNum (i); } /* ============= ED_PrintEdict_f For debugging, prints a single edicy ============= */ static void ED_PrintEdict_f (void) { int i; if (!sv.active) return; i = Q_atoi (Cmd_Argv(1)); if (i < 0 || i >= sv.num_edicts) { Con_Printf("Bad edict number\n"); return; } ED_PrintNum (i); } /* ============= ED_Count For debugging ============= */ static void ED_Count (void) { edict_t *ent; int i, active, models, solid, step; if (!sv.active) return; active = models = solid = step = 0; for (i = 0; i < sv.num_edicts; i++) { ent = EDICT_NUM(i); if (ent->free) continue; active++; if (ent->v.solid) solid++; if (ent->v.model) models++; if (ent->v.movetype == MOVETYPE_STEP) step++; } Con_Printf ("num_edicts:%3i\n", sv.num_edicts); Con_Printf ("active :%3i\n", active); Con_Printf ("view :%3i\n", models); Con_Printf ("touch :%3i\n", solid); Con_Printf ("step :%3i\n", step); } /* ============================================================================== ARCHIVING GLOBALS FIXME: need to tag constants, doesn't really work ============================================================================== */ /* ============= ED_WriteGlobals ============= */ void ED_WriteGlobals (FILE *f) { ddef_t *def; int i; const char *name; int type; fprintf (f, "{\n"); for (i = 0; i < progs->numglobaldefs; i++) { def = &pr_globaldefs[i]; type = def->type; if ( !(def->type & DEF_SAVEGLOBAL) ) continue; type &= ~DEF_SAVEGLOBAL; if (type != ev_string && type != ev_float && type != ev_entity) continue; name = PR_GetString(def->s_name); fprintf (f, "\"%s\" ", name); fprintf (f, "\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs])); } fprintf (f, "}\n"); } /* ============= ED_ParseGlobals ============= */ void ED_ParseGlobals (const char *data) { char keyname[64]; ddef_t *key; while (1) { // parse key data = COM_Parse (data); if (com_token[0] == '}') break; if (!data) Host_Error ("ED_ParseEntity: EOF without closing brace"); strcpy (keyname, com_token); // parse value data = COM_Parse (data); if (!data) Host_Error ("ED_ParseEntity: EOF without closing brace"); if (com_token[0] == '}') Host_Error ("ED_ParseEntity: closing brace without data"); key = ED_FindGlobal (keyname); if (!key) { Con_Printf ("'%s' is not a global\n", keyname); continue; } if (!ED_ParseEpair ((void *)pr_globals, key, com_token)) Host_Error ("ED_ParseGlobals: parse error"); } } //============================================================================ /* ============= ED_NewString ============= */ static string_t ED_NewString (const char *string) { char *new_p; int i, l; string_t num; l = strlen(string) + 1; num = PR_AllocString (l, &new_p); for (i = 0; i < l; i++) { if (string[i] == '\\' && i < l-1) { i++; if (string[i] == 'n') *new_p++ = '\n'; else *new_p++ = '\\'; } else *new_p++ = string[i]; } return num; } /* ============= ED_ParseEval Can parse either fields or globals returns false if error ============= */ static qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s) { int i; char string[128]; ddef_t *def; char *v, *w; void *d; dfunction_t *func; d = (void *)((int *)base + key->ofs); switch (key->type & ~DEF_SAVEGLOBAL) { case ev_string: *(string_t *)d = ED_NewString(s); break; case ev_float: *(float *)d = atof (s); break; case ev_vector: strcpy (string, s); v = string; w = string; for (i = 0; i < 3; i++) { while (*v && *v != ' ') v++; *v = 0; ((float *)d)[i] = atof (w); w = v = v+1; } break; case ev_entity: *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s))); break; case ev_field: def = ED_FindField (s); if (!def) { //johnfitz -- HACK -- suppress error becuase fog/sky fields might not be mentioned in defs.qc if (strncmp(s, "sky", 3) && strcmp(s, "fog")) Con_DPrintf ("Can't find field %s\n", s); return false; } *(int *)d = G_INT(def->ofs); break; case ev_function: func = ED_FindFunction (s); if (!func) { Con_Printf ("Can't find function %s\n", s); return false; } *(func_t *)d = func - pr_functions; break; default: break; } return true; } /* ==================== ED_ParseEdict Parses an edict out of the given string, returning the new position ed should be a properly initialized empty edict. Used for initial level load and for savegames. ==================== */ const char *ED_ParseEdict (const char *data, edict_t *ent) { ddef_t *key; char keyname[256]; qboolean anglehack, init; int n; init = false; // clear it if (ent != sv.edicts) // hack memset (&ent->v, 0, progs->entityfields * 4); // go through all the dictionary pairs while (1) { // parse key data = COM_Parse (data); if (com_token[0] == '}') break; if (!data) Host_Error ("ED_ParseEntity: EOF without closing brace"); // anglehack is to allow QuakeEd to write single scalar angles // and allow them to be turned into vectors. (FIXME...) if (!strcmp(com_token, "angle")) { strcpy (com_token, "angles"); anglehack = true; } else anglehack = false; // FIXME: change light to _light to get rid of this hack if (!strcmp(com_token, "light")) strcpy (com_token, "light_lev"); // hack for single light def strcpy (keyname, com_token); // another hack to fix keynames with trailing spaces n = strlen(keyname); while (n && keyname[n-1] == ' ') { keyname[n-1] = 0; n--; } // parse value data = COM_Parse (data); if (!data) Host_Error ("ED_ParseEntity: EOF without closing brace"); if (com_token[0] == '}') Host_Error ("ED_ParseEntity: closing brace without data"); init = true; // keynames with a leading underscore are used for utility comments, // and are immediately discarded by quake if (keyname[0] == '_') continue; //johnfitz -- hack to support .alpha even when progs.dat doesn't know about it if (!strcmp(keyname, "alpha")) ent->alpha = ENTALPHA_ENCODE(atof(com_token)); //johnfitz key = ED_FindField (keyname); if (!key) { //johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc if (strncmp(keyname, "sky", 3) && strcmp(keyname, "fog") && strcmp(keyname, "alpha")) Con_DPrintf ("\"%s\" is not a field\n", keyname); //johnfitz -- was Con_Printf continue; } if (anglehack) { char temp[32]; strcpy (temp, com_token); sprintf (com_token, "0 %s 0", temp); } if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) Host_Error ("ED_ParseEdict: parse error"); } if (!init) ent->free = true; return data; } /* ================ ED_LoadFromFile The entities are directly placed in the array, rather than allocated with ED_Alloc, because otherwise an error loading the map would have entity number references out of order. Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. Used for both fresh maps and savegame loads. A fresh map would also need to call ED_CallSpawnFunctions () to let the objects initialize themselves. ================ */ void ED_LoadFromFile (const char *data) { dfunction_t *func; edict_t *ent = NULL; int inhibit = 0; pr_global_struct->time = sv.time; // parse ents while (1) { // parse the opening brace data = COM_Parse (data); if (!data) break; if (com_token[0] != '{') Host_Error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = EDICT_NUM(0); else ent = ED_Alloc (); data = ED_ParseEdict (data, ent); // remove things from different skill levels or deathmatch if (deathmatch.value) { if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) { ED_Free (ent); inhibit++; continue; } } else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) { ED_Free (ent); inhibit++; continue; } // // immediately call spawn function // if (!ent->v.classname) { Con_SafePrintf ("No classname for:\n"); //johnfitz -- was Con_Printf ED_Print (ent); ED_Free (ent); continue; } // look for the spawn function func = ED_FindFunction ( PR_GetString(ent->v.classname) ); if (!func) { Con_SafePrintf ("No spawn function for:\n"); //johnfitz -- was Con_Printf ED_Print (ent); ED_Free (ent); continue; } pr_global_struct->self = EDICT_TO_PROG(ent); PR_ExecuteProgram (func - pr_functions); } Con_DPrintf ("%i entities inhibited\n", inhibit); } /* =============== PR_LoadProgs =============== */ void PR_LoadProgs (void) { int i; // flush the non-C variable lookup cache for (i = 0; i < GEFV_CACHESIZE; i++) gefvCache[i].field[0] = 0; CRC_Init (&pr_crc); progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat", NULL); if (!progs) Host_Error ("PR_LoadProgs: couldn't load progs.dat"); Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024); for (i = 0; i < com_filesize; i++) CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]); // byte swap the header for (i = 0; i < (int) sizeof(*progs) / 4; i++) ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] ); if (progs->version != PROG_VERSION) Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); if (progs->crc != PROGHEADER_CRC) Host_Error ("progs.dat system vars have been modified, progdefs.h is out of date"); pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_strings = (char *)progs + progs->ofs_strings; if (progs->ofs_strings + progs->numstrings >= com_filesize) Host_Error ("progs.dat strings go past end of file\n"); // initialize the strings pr_numknownstrings = 0; pr_maxknownstrings = 0; pr_stringssize = progs->numstrings; if (pr_knownstrings) Z_Free ((void *)pr_knownstrings); pr_knownstrings = NULL; PR_SetEngineString(""); pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); pr_globals = (float *)pr_global_struct; // byte swap the lumps for (i = 0; i < progs->numstatements; i++) { pr_statements[i].op = LittleShort(pr_statements[i].op); pr_statements[i].a = LittleShort(pr_statements[i].a); pr_statements[i].b = LittleShort(pr_statements[i].b); pr_statements[i].c = LittleShort(pr_statements[i].c); } for (i = 0; i < progs->numfunctions; i++) { pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); pr_functions[i].locals = LittleLong (pr_functions[i].locals); } for (i = 0; i < progs->numglobaldefs; i++) { pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); } pr_alpha_supported = false; //johnfitz for (i = 0; i < progs->numfielddefs; i++) { pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); //johnfitz -- detect alpha support in progs.dat if (!strcmp(pr_strings + pr_fielddefs[i].s_name,"alpha")) pr_alpha_supported = true; //johnfitz } for (i = 0; i < progs->numglobals; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); pr_edict_size = progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t); // round off to next highest whole word address (esp for Alpha) // this ensures that pointers in the engine data area are always // properly aligned pr_edict_size += sizeof(void *) - 1; pr_edict_size &= ~(sizeof(void *) - 1); } /* =============== PR_Init =============== */ void PR_Init (void) { Cmd_AddCommand ("edict", ED_PrintEdict_f); Cmd_AddCommand ("edicts", ED_PrintEdicts); Cmd_AddCommand ("edictcount", ED_Count); Cmd_AddCommand ("profile", PR_Profile_f); Cvar_RegisterVariable (&nomonsters); Cvar_RegisterVariable (&gamecfg); Cvar_RegisterVariable (&scratch1); Cvar_RegisterVariable (&scratch2); Cvar_RegisterVariable (&scratch3); Cvar_RegisterVariable (&scratch4); Cvar_RegisterVariable (&savedgamecfg); Cvar_RegisterVariable (&saved1); Cvar_RegisterVariable (&saved2); Cvar_RegisterVariable (&saved3); Cvar_RegisterVariable (&saved4); } edict_t *EDICT_NUM(int n) { if (n < 0 || n >= sv.max_edicts) Host_Error ("EDICT_NUM: bad number %i", n); return (edict_t *)((byte *)sv.edicts + (n)*pr_edict_size); } int NUM_FOR_EDICT(edict_t *e) { int b; b = (byte *)e - (byte *)sv.edicts; b = b / pr_edict_size; if (b < 0 || b >= sv.num_edicts) Host_Error ("NUM_FOR_EDICT: bad pointer"); return b; } //=========================================================================== #define PR_STRING_ALLOCSLOTS 256 static void PR_AllocStringSlots (void) { pr_maxknownstrings += PR_STRING_ALLOCSLOTS; Con_DPrintf2("PR_AllocStringSlots: realloc'ing for %d slots\n", pr_maxknownstrings); pr_knownstrings = (const char **) Z_Realloc ((void *)pr_knownstrings, pr_maxknownstrings * sizeof(char *)); } const char *PR_GetString (int num) { if (num >= 0 && num < pr_stringssize) return pr_strings + num; else if (num < 0 && num >= -pr_numknownstrings) { if (!pr_knownstrings[-1 - num]) { Host_Error ("PR_GetString: attempt to get a non-existant string %d\n", num); return ""; } return pr_knownstrings[-1 - num]; } else { Host_Error("PR_GetString: invalid string offset %d\n", num); return ""; } } int PR_SetEngineString (const char *s) { int i; if (!s) return 0; #if 0 /* can't: sv.model_precache & sv.sound_precache points to pr_strings */ if (s >= pr_strings && s <= pr_strings + pr_stringssize) Host_Error("PR_SetEngineString: \"%s\" in pr_strings area\n", s); #else if (s >= pr_strings && s <= pr_strings + pr_stringssize - 2) return (int)(s - pr_strings); #endif for (i = 0; i < pr_numknownstrings; i++) { if (pr_knownstrings[i] == s) return -1 - i; } // new unknown engine string //Con_DPrintf ("PR_SetEngineString: new engine string %p\n", s); #if 0 for (i = 0; i < pr_numknownstrings; i++) { if (!pr_knownstrings[i]) break; } #endif // if (i >= pr_numknownstrings) // { if (i >= pr_maxknownstrings) PR_AllocStringSlots(); pr_numknownstrings++; // } pr_knownstrings[i] = s; return -1 - i; } int PR_AllocString (int size, char **ptr) { int i; if (!size) return 0; for (i = 0; i < pr_numknownstrings; i++) { if (!pr_knownstrings[i]) break; } // if (i >= pr_numknownstrings) // { if (i >= pr_maxknownstrings) PR_AllocStringSlots(); pr_numknownstrings++; // } pr_knownstrings[i] = (char *)Hunk_AllocName(size, "string"); if (ptr) *ptr = (char *) pr_knownstrings[i]; return -1 - i; } �������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/build_cross_win64-sdl2.sh���������������������������������������������������0000755�0000000�0000000�00000000703�12475156650�020272� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # Change this script to meet your needs and/or environment. TARGET=x86_64-w64-mingw32 PREFIX=/opt/cross_win64 PATH="$PREFIX/bin:$PATH" export PATH MAKE_CMD=make CC="$TARGET-gcc" AS="$TARGET-as" RANLIB="$TARGET-ranlib" AR="$TARGET-ar" WINDRES="$TARGET-windres" STRIP="$TARGET-strip" export PATH CC AS AR RANLIB WINDRES STRIP exec $MAKE_CMD USE_SDL2=1 CC=$CC AS=$AS RANLIB=$RANLIB AR=$AR WINDRES=$WINDRES STRIP=$STRIP -f Makefile.w64 $* �������������������������������������������������������������quakespasm-0.91.0/Quake/snd_mem.c�������������������������������������������������������������������0000644�0000000�0000000�00000016051�12530666055�015320� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2011 O. Sezer <sezero@users.sourceforge.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // snd_mem.c: sound caching #include "quakedef.h" /* ================ ResampleSfx ================ */ static void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data) { int outcount; int srcsample; float stepscale; int i; int sample, samplefrac, fracstep; sfxcache_t *sc; sc = (sfxcache_t *) Cache_Check (&sfx->cache); if (!sc) return; stepscale = (float)inrate / shm->speed; // this is usually 0.5, 1, or 2 outcount = sc->length / stepscale; sc->length = outcount; if (sc->loopstart != -1) sc->loopstart = sc->loopstart / stepscale; sc->speed = shm->speed; if (loadas8bit.value) sc->width = 1; else sc->width = inwidth; sc->stereo = 0; // resample / decimate to the current source rate if (stepscale == 1 && inwidth == 1 && sc->width == 1) { // fast special case for (i = 0; i < outcount; i++) ((signed char *)sc->data)[i] = (int)( (unsigned char)(data[i]) - 128); } else { // general case samplefrac = 0; fracstep = stepscale*256; for (i = 0; i < outcount; i++) { srcsample = samplefrac >> 8; samplefrac += fracstep; if (inwidth == 2) sample = LittleShort ( ((short *)data)[srcsample] ); else sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8; if (sc->width == 2) ((short *)sc->data)[i] = sample; else ((signed char *)sc->data)[i] = sample >> 8; } } } //============================================================================= /* ============== S_LoadSound ============== */ sfxcache_t *S_LoadSound (sfx_t *s) { char namebuffer[256]; byte *data; wavinfo_t info; int len; float stepscale; sfxcache_t *sc; byte stackbuf[1*1024]; // avoid dirtying the cache heap // see if still in memory sc = (sfxcache_t *) Cache_Check (&s->cache); if (sc) return sc; // Con_Printf ("S_LoadSound: %x\n", (int)stackbuf); // load it in q_strlcpy(namebuffer, "sound/", sizeof(namebuffer)); q_strlcat(namebuffer, s->name, sizeof(namebuffer)); // Con_Printf ("loading %s\n",namebuffer); data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf), NULL); if (!data) { Con_Printf ("Couldn't load %s\n", namebuffer); return NULL; } info = GetWavinfo (s->name, data, com_filesize); if (info.channels != 1) { Con_Printf ("%s is a stereo sample\n",s->name); return NULL; } if (info.width != 1 && info.width != 2) { Con_Printf("%s is not 8 or 16 bit\n", s->name); return NULL; } stepscale = (float)info.rate / shm->speed; len = info.samples / stepscale; len = len * info.width * info.channels; if (info.samples == 0 || len == 0) { Con_Printf("%s has zero samples\n", s->name); return NULL; } sc = (sfxcache_t *) Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name); if (!sc) return NULL; sc->length = info.samples; sc->loopstart = info.loopstart; sc->speed = info.rate; sc->width = info.width; sc->stereo = info.channels; ResampleSfx (s, sc->speed, sc->width, data + info.dataofs); return sc; } /* =============================================================================== WAV loading =============================================================================== */ static byte *data_p; static byte *iff_end; static byte *last_chunk; static byte *iff_data; static int iff_chunk_len; static short GetLittleShort (void) { short val = 0; val = *data_p; val = val + (*(data_p+1)<<8); data_p += 2; return val; } static int GetLittleLong (void) { int val = 0; val = *data_p; val = val + (*(data_p+1)<<8); val = val + (*(data_p+2)<<16); val = val + (*(data_p+3)<<24); data_p += 4; return val; } static void FindNextChunk (const char *name) { while (1) { // Need at least 8 bytes for a chunk if (last_chunk + 8 >= iff_end) { data_p = NULL; return; } data_p = last_chunk + 4; iff_chunk_len = GetLittleLong(); if (iff_chunk_len < 0 || iff_chunk_len > iff_end - data_p) { data_p = NULL; Con_DPrintf2("bad \"%s\" chunk length (%d)\n", name, iff_chunk_len); return; } last_chunk = data_p + ((iff_chunk_len + 1) & ~1); data_p -= 8; if (!Q_strncmp((char *)data_p, name, 4)) return; } } static void FindChunk (const char *name) { last_chunk = iff_data; FindNextChunk (name); } #if 0 static void DumpChunks (void) { char str[5]; str[4] = 0; data_p = iff_data; do { memcpy (str, data_p, 4); data_p += 4; iff_chunk_len = GetLittleLong(); Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); data_p += (iff_chunk_len + 1) & ~1; } while (data_p < iff_end); } #endif /* ============ GetWavinfo ============ */ wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength) { wavinfo_t info; int i; int format; int samples; memset (&info, 0, sizeof(info)); if (!wav) return info; iff_data = wav; iff_end = wav + wavlength; // find "RIFF" chunk FindChunk("RIFF"); if (!(data_p && !Q_strncmp((char *)data_p + 8, "WAVE", 4))) { Con_Printf("%s missing RIFF/WAVE chunks\n", name); return info; } // get "fmt " chunk iff_data = data_p + 12; #if 0 DumpChunks (); #endif FindChunk("fmt "); if (!data_p) { Con_Printf("%s is missing fmt chunk\n", name); return info; } data_p += 8; format = GetLittleShort(); if (format != WAV_FORMAT_PCM) { Con_Printf("%s is not Microsoft PCM format\n", name); return info; } info.channels = GetLittleShort(); info.rate = GetLittleLong(); data_p += 4 + 2; i = GetLittleShort(); if (i != 8 && i != 16) return info; info.width = i / 8; // get cue chunk FindChunk("cue "); if (data_p) { data_p += 32; info.loopstart = GetLittleLong(); // Con_Printf("loopstart=%d\n", sfx->loopstart); // if the next chunk is a LIST chunk, look for a cue length marker FindNextChunk ("LIST"); if (data_p) { if (!strncmp((char *)data_p + 28, "mark", 4)) { // this is not a proper parse, but it works with cooledit... data_p += 24; i = GetLittleLong(); // samples in loop info.samples = info.loopstart + i; // Con_Printf("looped length: %i\n", i); } } } else info.loopstart = -1; // find data chunk FindChunk("data"); if (!data_p) { Con_Printf("%s is missing data chunk\n", name); return info; } data_p += 4; samples = GetLittleLong() / info.width; if (info.samples) { if (samples < info.samples) Sys_Error ("%s has a bad loop length", name); } else info.samples = samples; info.dataofs = data_p - wav; return info; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sbar.c����������������������������������������������������������������������0000644�0000000�0000000�00000074146�12604663666�014645� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sbar.c -- status bar code #include "quakedef.h" int sb_updates; // if >= vid.numpages, no update needed #define STAT_MINUS 10 // num frame for '-' stats digit qpic_t *sb_nums[2][11]; qpic_t *sb_colon, *sb_slash; qpic_t *sb_ibar; qpic_t *sb_sbar; qpic_t *sb_scorebar; qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes qpic_t *sb_ammo[4]; qpic_t *sb_sigil[4]; qpic_t *sb_armor[3]; qpic_t *sb_items[32]; qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive // 0 is static, 1 is temporary animation qpic_t *sb_face_invis; qpic_t *sb_face_quad; qpic_t *sb_face_invuln; qpic_t *sb_face_invis_invuln; qboolean sb_showscores; int sb_lines; // scan lines to draw qpic_t *rsb_invbar[2]; qpic_t *rsb_weapons[5]; qpic_t *rsb_items[2]; qpic_t *rsb_ammo[3]; qpic_t *rsb_teambord; // PGM 01/19/97 - team color border //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher qpic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes //MED 01/04/97 added array to simplify weapon parsing int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT}; //MED 01/04/97 added hipnotic items array qpic_t *hsb_items[2]; void Sbar_MiniDeathmatchOverlay (void); void Sbar_DeathmatchOverlay (void); void M_DrawPic (int x, int y, qpic_t *pic); /* =============== Sbar_ShowScores Tab key down =============== */ void Sbar_ShowScores (void) { if (sb_showscores) return; sb_showscores = true; sb_updates = 0; } /* =============== Sbar_DontShowScores Tab key up =============== */ void Sbar_DontShowScores (void) { sb_showscores = false; sb_updates = 0; } /* =============== Sbar_Changed =============== */ void Sbar_Changed (void) { sb_updates = 0; // update next frame } /* =============== Sbar_LoadPics -- johnfitz -- load all the sbar pics =============== */ void Sbar_LoadPics (void) { int i; for (i = 0; i < 10; i++) { sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i)); sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i)); } sb_nums[0][10] = Draw_PicFromWad ("num_minus"); sb_nums[1][10] = Draw_PicFromWad ("anum_minus"); sb_colon = Draw_PicFromWad ("num_colon"); sb_slash = Draw_PicFromWad ("num_slash"); sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun"); sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun"); sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun"); sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun"); sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch"); sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch"); sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng"); sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun"); sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun"); sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun"); sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun"); sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch"); sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch"); sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng"); for (i = 0; i < 5; i++) { sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1)); sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1)); sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1)); sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1)); sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1)); sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1)); sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1)); } sb_ammo[0] = Draw_PicFromWad ("sb_shells"); sb_ammo[1] = Draw_PicFromWad ("sb_nails"); sb_ammo[2] = Draw_PicFromWad ("sb_rocket"); sb_ammo[3] = Draw_PicFromWad ("sb_cells"); sb_armor[0] = Draw_PicFromWad ("sb_armor1"); sb_armor[1] = Draw_PicFromWad ("sb_armor2"); sb_armor[2] = Draw_PicFromWad ("sb_armor3"); sb_items[0] = Draw_PicFromWad ("sb_key1"); sb_items[1] = Draw_PicFromWad ("sb_key2"); sb_items[2] = Draw_PicFromWad ("sb_invis"); sb_items[3] = Draw_PicFromWad ("sb_invuln"); sb_items[4] = Draw_PicFromWad ("sb_suit"); sb_items[5] = Draw_PicFromWad ("sb_quad"); sb_sigil[0] = Draw_PicFromWad ("sb_sigil1"); sb_sigil[1] = Draw_PicFromWad ("sb_sigil2"); sb_sigil[2] = Draw_PicFromWad ("sb_sigil3"); sb_sigil[3] = Draw_PicFromWad ("sb_sigil4"); sb_faces[4][0] = Draw_PicFromWad ("face1"); sb_faces[4][1] = Draw_PicFromWad ("face_p1"); sb_faces[3][0] = Draw_PicFromWad ("face2"); sb_faces[3][1] = Draw_PicFromWad ("face_p2"); sb_faces[2][0] = Draw_PicFromWad ("face3"); sb_faces[2][1] = Draw_PicFromWad ("face_p3"); sb_faces[1][0] = Draw_PicFromWad ("face4"); sb_faces[1][1] = Draw_PicFromWad ("face_p4"); sb_faces[0][0] = Draw_PicFromWad ("face5"); sb_faces[0][1] = Draw_PicFromWad ("face_p5"); sb_face_invis = Draw_PicFromWad ("face_invis"); sb_face_invuln = Draw_PicFromWad ("face_invul2"); sb_face_invis_invuln = Draw_PicFromWad ("face_inv2"); sb_face_quad = Draw_PicFromWad ("face_quad"); sb_sbar = Draw_PicFromWad ("sbar"); sb_ibar = Draw_PicFromWad ("ibar"); sb_scorebar = Draw_PicFromWad ("scorebar"); //MED 01/04/97 added new hipnotic weapons if (hipnotic) { hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser"); hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir"); hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox"); hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren"); hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox"); hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser"); hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir"); hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox"); hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren"); hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox"); for (i = 0; i < 5; i++) { hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1)); hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1)); hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1)); hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1)); hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1)); } hsb_items[0] = Draw_PicFromWad ("sb_wsuit"); hsb_items[1] = Draw_PicFromWad ("sb_eshld"); } if (rogue) { rsb_invbar[0] = Draw_PicFromWad ("r_invbar1"); rsb_invbar[1] = Draw_PicFromWad ("r_invbar2"); rsb_weapons[0] = Draw_PicFromWad ("r_lava"); rsb_weapons[1] = Draw_PicFromWad ("r_superlava"); rsb_weapons[2] = Draw_PicFromWad ("r_gren"); rsb_weapons[3] = Draw_PicFromWad ("r_multirock"); rsb_weapons[4] = Draw_PicFromWad ("r_plasma"); rsb_items[0] = Draw_PicFromWad ("r_shield1"); rsb_items[1] = Draw_PicFromWad ("r_agrav1"); // PGM 01/19/97 - team color border rsb_teambord = Draw_PicFromWad ("r_teambord"); // PGM 01/19/97 - team color border rsb_ammo[0] = Draw_PicFromWad ("r_ammolava"); rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti"); rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma"); } } /* =============== Sbar_Init -- johnfitz -- rewritten =============== */ void Sbar_Init (void) { Cmd_AddCommand ("+showscores", Sbar_ShowScores); Cmd_AddCommand ("-showscores", Sbar_DontShowScores); Sbar_LoadPics (); } //============================================================================= // drawing routines are relative to the status bar location /* ============= Sbar_DrawPic -- johnfitz -- rewritten now that GL_SetCanvas is doing the work ============= */ void Sbar_DrawPic (int x, int y, qpic_t *pic) { Draw_Pic (x, y + 24, pic); } /* ============= Sbar_DrawPicAlpha -- johnfitz ============= */ void Sbar_DrawPicAlpha (int x, int y, qpic_t *pic, float alpha) { glDisable (GL_ALPHA_TEST); glEnable (GL_BLEND); glColor4f(1,1,1,alpha); Draw_Pic (x, y + 24, pic); glColor4f(1,1,1,1); // ericw -- changed from glColor3f to work around intel 855 bug with "r_oldwater 0" and "scr_sbaralpha 0" glDisable (GL_BLEND); glEnable (GL_ALPHA_TEST); } /* ================ Sbar_DrawCharacter -- johnfitz -- rewritten now that GL_SetCanvas is doing the work ================ */ void Sbar_DrawCharacter (int x, int y, int num) { Draw_Character (x, y + 24, num); } /* ================ Sbar_DrawString -- johnfitz -- rewritten now that GL_SetCanvas is doing the work ================ */ void Sbar_DrawString (int x, int y, const char *str) { Draw_String (x, y + 24, str); } /* =============== Sbar_DrawScrollString -- johnfitz scroll the string inside a glscissor region =============== */ void Sbar_DrawScrollString (int x, int y, int width, const char *str) { float scale; int len, ofs, left; scale = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); left = x * scale; if (cl.gametype != GAME_DEATHMATCH) left += (((float)glwidth - 320.0 * scale) / 2); glEnable (GL_SCISSOR_TEST); glScissor (left, 0, width * scale, glheight); len = strlen(str)*8 + 40; ofs = ((int)(realtime*30))%len; Sbar_DrawString (x - ofs, y, str); Sbar_DrawCharacter (x - ofs + len - 32, y, '/'); Sbar_DrawCharacter (x - ofs + len - 24, y, '/'); Sbar_DrawCharacter (x - ofs + len - 16, y, '/'); Sbar_DrawString (x - ofs + len, y, str); glDisable (GL_SCISSOR_TEST); } /* ============= Sbar_itoa ============= */ int Sbar_itoa (int num, char *buf) { char *str; int pow10; int dig; str = buf; if (num < 0) { *str++ = '-'; num = -num; } for (pow10 = 10 ; num >= pow10 ; pow10 *= 10) ; do { pow10 /= 10; dig = num/pow10; *str++ = '0'+dig; num -= dig*pow10; } while (pow10 != 1); *str = 0; return str-buf; } /* ============= Sbar_DrawNum ============= */ void Sbar_DrawNum (int x, int y, int num, int digits, int color) { char str[12]; char *ptr; int l, frame; num = q_min(999,num); //johnfitz -- cap high values rather than truncating number l = Sbar_itoa (num, str); ptr = str; if (l > digits) ptr += (l-digits); if (l < digits) x += (digits-l)*24; while (*ptr) { if (*ptr == '-') frame = STAT_MINUS; else frame = *ptr -'0'; Sbar_DrawPic (x,y,sb_nums[color][frame]); //johnfitz -- DrawTransPic is obsolete x += 24; ptr++; } } //============================================================================= int fragsort[MAX_SCOREBOARD]; char scoreboardtext[MAX_SCOREBOARD][20]; int scoreboardtop[MAX_SCOREBOARD]; int scoreboardbottom[MAX_SCOREBOARD]; int scoreboardcount[MAX_SCOREBOARD]; int scoreboardlines; /* =============== Sbar_SortFrags =============== */ void Sbar_SortFrags (void) { int i, j, k; // sort by frags scoreboardlines = 0; for (i = 0; i < cl.maxclients; i++) { if (cl.scores[i].name[0]) { fragsort[scoreboardlines] = i; scoreboardlines++; } } for (i = 0; i < scoreboardlines; i++) { for (j = 0; j < scoreboardlines - 1 - i; j++) { if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags) { k = fragsort[j]; fragsort[j] = fragsort[j+1]; fragsort[j+1] = k; } } } } int Sbar_ColorForMap (int m) { return m < 128 ? m + 8 : m + 8; } /* =============== Sbar_UpdateScoreboard =============== */ void Sbar_UpdateScoreboard (void) { int i, k; int top, bottom; scoreboard_t *s; Sbar_SortFrags (); // draw the text memset (scoreboardtext, 0, sizeof(scoreboardtext)); for (i = 0; i < scoreboardlines; i++) { k = fragsort[i]; s = &cl.scores[k]; sprintf (&scoreboardtext[i][1], "%3i %s", s->frags, s->name); top = s->colors & 0xf0; bottom = (s->colors & 15) <<4; scoreboardtop[i] = Sbar_ColorForMap (top); scoreboardbottom[i] = Sbar_ColorForMap (bottom); } } /* =============== Sbar_SoloScoreboard -- johnfitz -- new layout =============== */ void Sbar_SoloScoreboard (void) { char str[256]; int minutes, seconds, tens, units; int len; sprintf (str,"Kills: %i/%i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); Sbar_DrawString (8, 12, str); sprintf (str,"Secrets: %i/%i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]); Sbar_DrawString (312 - strlen(str)*8, 12, str); if (!fitzmode) { /* QuakeSpasm customization: */ q_snprintf (str, sizeof(str), "skill %i", (int)(skill.value + 0.5)); Sbar_DrawString (160 - strlen(str)*4, 12, str); q_snprintf (str, sizeof(str), "%s (%s)", cl.levelname, cl.mapname); len = strlen (str); if (len > 40) Sbar_DrawScrollString (0, 4, 320, str); else Sbar_DrawString (160 - len*4, 4, str); return; } minutes = cl.time / 60; seconds = cl.time - 60*minutes; tens = seconds / 10; units = seconds - 10*tens; sprintf (str,"%i:%i%i", minutes, tens, units); Sbar_DrawString (160 - strlen(str)*4, 12, str); len = strlen (cl.levelname); if (len > 40) Sbar_DrawScrollString (0, 4, 320, cl.levelname); else Sbar_DrawString (160 - len*4, 4, cl.levelname); } /* =============== Sbar_DrawScoreboard =============== */ void Sbar_DrawScoreboard (void) { Sbar_SoloScoreboard (); if (cl.gametype == GAME_DEATHMATCH) Sbar_DeathmatchOverlay (); } //============================================================================= /* =============== Sbar_DrawInventory =============== */ void Sbar_DrawInventory (void) { int i; char num[6]; float time; int flashon; if (rogue) { if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) Sbar_DrawPicAlpha (0, -24, rsb_invbar[0], scr_sbaralpha.value); //johnfitz -- scr_sbaralpha else Sbar_DrawPicAlpha (0, -24, rsb_invbar[1], scr_sbaralpha.value); //johnfitz -- scr_sbaralpha } else { Sbar_DrawPicAlpha (0, -24, sb_ibar, scr_sbaralpha.value); //johnfitz -- scr_sbaralpha } // weapons for (i = 0; i < 7; i++) { if (cl.items & (IT_SHOTGUN<<i) ) { time = cl.item_gettime[i]; flashon = (int)((cl.time - time)*10); if (flashon >= 10) { if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) ) flashon = 1; else flashon = 0; } else flashon = (flashon%5) + 2; Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]); if (flashon > 1) sb_updates = 0; // force update to remove flash } } // MED 01/04/97 // hipnotic weapons if (hipnotic) { int grenadeflashing = 0; for (i = 0; i < 4; i++) { if (cl.items & (1<<hipweapons[i])) { time = cl.item_gettime[hipweapons[i]]; flashon = (int)((cl.time - time)*10); if (flashon >= 10) { if (cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])) flashon = 1; else flashon = 0; } else flashon = (flashon%5) + 2; // check grenade launcher if (i == 2) { if (cl.items & HIT_PROXIMITY_GUN) { if (flashon) { grenadeflashing = 1; Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]); } } } else if (i == 3) { if (cl.items & (IT_SHOTGUN<<4)) { if (flashon && !grenadeflashing) { Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]); } else if (!grenadeflashing) { Sbar_DrawPic (96, -16, hsb_weapons[0][3]); } } else Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]); } else Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]); if (flashon > 1) sb_updates = 0; // force update to remove flash } } } if (rogue) { // check for powered up weapon. if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) { for (i=0;i<5;i++) { if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i)) { Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]); } } } } // ammo counts for (i = 0; i < 4; i++) { sprintf (num, "%3i", q_min(999,cl.stats[STAT_SHELLS+i])); //johnfitz -- cap displayed value to 999 if (num[0] != ' ') Sbar_DrawCharacter ( (6*i+1)*8 + 2, -24, 18 + num[0] - '0'); if (num[1] != ' ') Sbar_DrawCharacter ( (6*i+2)*8 + 2, -24, 18 + num[1] - '0'); if (num[2] != ' ') Sbar_DrawCharacter ( (6*i+3)*8 + 2, -24, 18 + num[2] - '0'); } flashon = 0; // items for (i = 0; i < 6; i++) { if (cl.items & (1<<(17+i))) { time = cl.item_gettime[17+i]; if (time && time > cl.time - 2 && flashon) { // flash frame sb_updates = 0; } else { //MED 01/04/97 changed keys if (!hipnotic || (i > 1)) { Sbar_DrawPic (192 + i*16, -16, sb_items[i]); } } if (time && time > cl.time - 2) sb_updates = 0; } } //MED 01/04/97 added hipnotic items // hipnotic items if (hipnotic) { for (i = 0; i < 2; i++) { if (cl.items & (1<<(24+i))) { time = cl.item_gettime[24+i]; if (time && time > cl.time - 2 && flashon ) { // flash frame sb_updates = 0; } else { Sbar_DrawPic (288 + i*16, -16, hsb_items[i]); } if (time && time > cl.time - 2) sb_updates = 0; } } } if (rogue) { // new rogue items for (i = 0; i < 2; i++) { if (cl.items & (1<<(29+i))) { time = cl.item_gettime[29+i]; if (time && time > cl.time - 2 && flashon) { // flash frame sb_updates = 0; } else { Sbar_DrawPic (288 + i*16, -16, rsb_items[i]); } if (time && time > cl.time - 2) sb_updates = 0; } } } else { // sigils for (i = 0; i < 4; i++) { if (cl.items & (1<<(28+i))) { time = cl.item_gettime[28+i]; if (time && time > cl.time - 2 && flashon) { // flash frame sb_updates = 0; } else Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]); if (time && time > cl.time - 2) sb_updates = 0; } } } } //============================================================================= /* =============== Sbar_DrawFrags -- johnfitz -- heavy revision =============== */ void Sbar_DrawFrags (void) { int numscores, i, x, color; char num[12]; scoreboard_t *s; Sbar_SortFrags (); // draw the text numscores = q_min(scoreboardlines, 4); for (i = 0, x = 184; i<numscores; i++, x += 32) { s = &cl.scores[fragsort[i]]; if (!s->name[0]) continue; // top color color = s->colors & 0xf0; color = Sbar_ColorForMap (color); Draw_Fill (x + 10, 1, 28, 4, color, 1); // bottom color color = (s->colors & 15)<<4; color = Sbar_ColorForMap (color); Draw_Fill (x + 10, 5, 28, 3, color, 1); // number sprintf (num, "%3i", s->frags); Sbar_DrawCharacter (x + 12, -24, num[0]); Sbar_DrawCharacter (x + 20, -24, num[1]); Sbar_DrawCharacter (x + 28, -24, num[2]); // brackets if (fragsort[i] == cl.viewentity - 1) { Sbar_DrawCharacter (x + 6, -24, 16); Sbar_DrawCharacter (x + 32, -24, 17); } } } //============================================================================= /* =============== Sbar_DrawFace =============== */ void Sbar_DrawFace (void) { int f, anim; // PGM 01/19/97 - team color drawing // PGM 03/02/97 - fixed so color swatch only appears in CTF modes if (rogue && (cl.maxclients != 1) && (teamplay.value>3) && (teamplay.value<7)) { int top, bottom; int xofs; char num[12]; scoreboard_t *s; s = &cl.scores[cl.viewentity - 1]; // draw background top = s->colors & 0xf0; bottom = (s->colors & 15)<<4; top = Sbar_ColorForMap (top); bottom = Sbar_ColorForMap (bottom); if (cl.gametype == GAME_DEATHMATCH) xofs = 113; else xofs = ((vid.width - 320)>>1) + 113; Sbar_DrawPic (112, 0, rsb_teambord); Draw_Fill (xofs, /*vid.height-*/24+3, 22, 9, top, 1); //johnfitz -- sbar coords are now relative Draw_Fill (xofs, /*vid.height-*/24+12, 22, 9, bottom, 1); //johnfitz -- sbar coords are now relative // draw number f = s->frags; sprintf (num, "%3i",f); if (top == 8) { if (num[0] != ' ') Sbar_DrawCharacter(113, 3, 18 + num[0] - '0'); if (num[1] != ' ') Sbar_DrawCharacter(120, 3, 18 + num[1] - '0'); if (num[2] != ' ') Sbar_DrawCharacter(127, 3, 18 + num[2] - '0'); } else { Sbar_DrawCharacter (113, 3, num[0]); Sbar_DrawCharacter (120, 3, num[1]); Sbar_DrawCharacter (127, 3, num[2]); } return; } // PGM 01/19/97 - team color drawing if ((cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY)) == (IT_INVISIBILITY | IT_INVULNERABILITY)) { Sbar_DrawPic (112, 0, sb_face_invis_invuln); return; } if (cl.items & IT_QUAD) { Sbar_DrawPic (112, 0, sb_face_quad ); return; } if (cl.items & IT_INVISIBILITY) { Sbar_DrawPic (112, 0, sb_face_invis ); return; } if (cl.items & IT_INVULNERABILITY) { Sbar_DrawPic (112, 0, sb_face_invuln); return; } if (cl.stats[STAT_HEALTH] >= 100) f = 4; else f = cl.stats[STAT_HEALTH] / 20; if (f < 0) // in case we ever decide to draw when health <= 0 f = 0; if (cl.time <= cl.faceanimtime) { anim = 1; sb_updates = 0; // make sure the anim gets drawn over } else anim = 0; Sbar_DrawPic (112, 0, sb_faces[f][anim]); } /* =============== Sbar_Draw =============== */ void Sbar_Draw (void) { float w; //johnfitz if (scr_con_current == vid.height) return; // console is full screen if (cl.intermission) return; //johnfitz -- never draw sbar during intermission if (sb_updates >= vid.numpages && !gl_clear.value && scr_sbaralpha.value >= 1 //johnfitz -- gl_clear, scr_sbaralpha && !(gl_glsl_gamma_able && vid_gamma.value != 1)) //ericw -- must draw sbar every frame if doing glsl gamma return; sb_updates++; GL_SetCanvas (CANVAS_DEFAULT); //johnfitz //johnfitz -- don't waste fillrate by clearing the area behind the sbar w = CLAMP (320.0f, scr_sbarscale.value * 320.0f, (float)glwidth); if (sb_lines && glwidth > w) { if (scr_sbaralpha.value < 1) Draw_TileClear (0, glheight - sb_lines, glwidth, sb_lines); if (cl.gametype == GAME_DEATHMATCH) Draw_TileClear (w, glheight - sb_lines, glwidth - w, sb_lines); else { Draw_TileClear (0, glheight - sb_lines, (glwidth - w) / 2.0f, sb_lines); Draw_TileClear ((glwidth - w) / 2.0f + w, glheight - sb_lines, (glwidth - w) / 2.0f, sb_lines); } } //johnfitz GL_SetCanvas (CANVAS_SBAR); //johnfitz if (scr_viewsize.value < 110) //johnfitz -- check viewsize instead of sb_lines { Sbar_DrawInventory (); if (cl.maxclients != 1) Sbar_DrawFrags (); } if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) { Sbar_DrawPicAlpha (0, 0, sb_scorebar, scr_sbaralpha.value); //johnfitz -- scr_sbaralpha Sbar_DrawScoreboard (); sb_updates = 0; } else if (scr_viewsize.value < 120) //johnfitz -- check viewsize instead of sb_lines { Sbar_DrawPicAlpha (0, 0, sb_sbar, scr_sbaralpha.value); //johnfitz -- scr_sbaralpha // keys (hipnotic only) //MED 01/04/97 moved keys here so they would not be overwritten if (hipnotic) { if (cl.items & IT_KEY1) Sbar_DrawPic (209, 3, sb_items[0]); if (cl.items & IT_KEY2) Sbar_DrawPic (209, 12, sb_items[1]); } // armor if (cl.items & IT_INVULNERABILITY) { Sbar_DrawNum (24, 0, 666, 3, 1); Sbar_DrawPic (0, 0, draw_disc); } else { if (rogue) { Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25); if (cl.items & RIT_ARMOR3) Sbar_DrawPic (0, 0, sb_armor[2]); else if (cl.items & RIT_ARMOR2) Sbar_DrawPic (0, 0, sb_armor[1]); else if (cl.items & RIT_ARMOR1) Sbar_DrawPic (0, 0, sb_armor[0]); } else { Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3 , cl.stats[STAT_ARMOR] <= 25); if (cl.items & IT_ARMOR3) Sbar_DrawPic (0, 0, sb_armor[2]); else if (cl.items & IT_ARMOR2) Sbar_DrawPic (0, 0, sb_armor[1]); else if (cl.items & IT_ARMOR1) Sbar_DrawPic (0, 0, sb_armor[0]); } } // face Sbar_DrawFace (); // health Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3 , cl.stats[STAT_HEALTH] <= 25); // ammo icon if (rogue) { if (cl.items & RIT_SHELLS) Sbar_DrawPic (224, 0, sb_ammo[0]); else if (cl.items & RIT_NAILS) Sbar_DrawPic (224, 0, sb_ammo[1]); else if (cl.items & RIT_ROCKETS) Sbar_DrawPic (224, 0, sb_ammo[2]); else if (cl.items & RIT_CELLS) Sbar_DrawPic (224, 0, sb_ammo[3]); else if (cl.items & RIT_LAVA_NAILS) Sbar_DrawPic (224, 0, rsb_ammo[0]); else if (cl.items & RIT_PLASMA_AMMO) Sbar_DrawPic (224, 0, rsb_ammo[1]); else if (cl.items & RIT_MULTI_ROCKETS) Sbar_DrawPic (224, 0, rsb_ammo[2]); } else { if (cl.items & IT_SHELLS) Sbar_DrawPic (224, 0, sb_ammo[0]); else if (cl.items & IT_NAILS) Sbar_DrawPic (224, 0, sb_ammo[1]); else if (cl.items & IT_ROCKETS) Sbar_DrawPic (224, 0, sb_ammo[2]); else if (cl.items & IT_CELLS) Sbar_DrawPic (224, 0, sb_ammo[3]); } Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10); } //johnfitz -- removed the vid.width > 320 check here if (cl.gametype == GAME_DEATHMATCH) Sbar_MiniDeathmatchOverlay (); } //============================================================================= /* ================== Sbar_IntermissionNumber ================== */ void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color) { char str[12]; char *ptr; int l, frame; l = Sbar_itoa (num, str); ptr = str; if (l > digits) ptr += (l-digits); if (l < digits) x += (digits-l)*24; while (*ptr) { if (*ptr == '-') frame = STAT_MINUS; else frame = *ptr -'0'; Draw_Pic (x,y,sb_nums[color][frame]); //johnfitz -- stretched menus x += 24; ptr++; } } /* ================== Sbar_DeathmatchOverlay ================== */ void Sbar_DeathmatchOverlay (void) { qpic_t *pic; int i, k, l; int top, bottom; int x, y, f; char num[12]; scoreboard_t *s; GL_SetCanvas (CANVAS_MENU); //johnfitz pic = Draw_CachePic ("gfx/ranking.lmp"); M_DrawPic ((320-pic->width)/2, 8, pic); // scores Sbar_SortFrags (); // draw the text l = scoreboardlines; x = 80; //johnfitz -- simplified becuase some positioning is handled elsewhere y = 40; for (i = 0; i < l; i++) { k = fragsort[i]; s = &cl.scores[k]; if (!s->name[0]) continue; // draw background top = s->colors & 0xf0; bottom = (s->colors & 15)<<4; top = Sbar_ColorForMap (top); bottom = Sbar_ColorForMap (bottom); Draw_Fill ( x, y, 40, 4, top, 1); //johnfitz -- stretched overlays Draw_Fill ( x, y+4, 40, 4, bottom, 1); //johnfitz -- stretched overlays // draw number f = s->frags; sprintf (num, "%3i",f); Draw_Character ( x+8 , y, num[0]); //johnfitz -- stretched overlays Draw_Character ( x+16 , y, num[1]); //johnfitz -- stretched overlays Draw_Character ( x+24 , y, num[2]); //johnfitz -- stretched overlays if (k == cl.viewentity - 1) Draw_Character ( x - 8, y, 12); //johnfitz -- stretched overlays #if 0 { int total; int n, minutes, tens, units; // draw time total = cl.completed_time - s->entertime; minutes = (int)total/60; n = total - minutes*60; tens = n/10; units = n%10; sprintf (num, "%3i:%i%i", minutes, tens, units); M_Print ( x+48 , y, num); //johnfitz -- was Draw_String, changed for stretched overlays } #endif // draw name M_Print (x+64, y, s->name); //johnfitz -- was Draw_String, changed for stretched overlays y += 10; } GL_SetCanvas (CANVAS_SBAR); //johnfitz } /* ================== Sbar_MiniDeathmatchOverlay ================== */ void Sbar_MiniDeathmatchOverlay (void) { int i, k, top, bottom, x, y, f, numlines; char num[12]; float scale; //johnfitz scoreboard_t *s; scale = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); //johnfitz //MAX_SCOREBOARDNAME = 32, so total width for this overlay plus sbar is 632, but we can cut off some i guess if (glwidth/scale < 512 || scr_viewsize.value >= 120) //johnfitz -- test should consider scr_sbarscale return; // scores Sbar_SortFrags (); // draw the text numlines = (scr_viewsize.value >= 110) ? 3 : 6; //johnfitz //find us for (i = 0; i < scoreboardlines; i++) if (fragsort[i] == cl.viewentity - 1) break; if (i == scoreboardlines) // we're not there i = 0; else // figure out start i = i - numlines/2; if (i > scoreboardlines - numlines) i = scoreboardlines - numlines; if (i < 0) i = 0; x = 324; y = (scr_viewsize.value >= 110) ? 24 : 0; //johnfitz -- start at the right place for ( ; i < scoreboardlines && y <= 48; i++, y+=8) //johnfitz -- change y init, test, inc { k = fragsort[i]; s = &cl.scores[k]; if (!s->name[0]) continue; // colors top = s->colors & 0xf0; bottom = (s->colors & 15)<<4; top = Sbar_ColorForMap (top); bottom = Sbar_ColorForMap (bottom); Draw_Fill (x, y+1, 40, 4, top, 1); Draw_Fill (x, y+5, 40, 3, bottom, 1); // number f = s->frags; sprintf (num, "%3i",f); Draw_Character (x+ 8, y, num[0]); Draw_Character (x+16, y, num[1]); Draw_Character (x+24, y, num[2]); // brackets if (k == cl.viewentity - 1) { Draw_Character (x, y, 16); Draw_Character (x+32, y, 17); } // name Draw_String (x+48, y, s->name); } } /* ================== Sbar_IntermissionOverlay ================== */ void Sbar_IntermissionOverlay (void) { qpic_t *pic; int dig; int num; if (cl.gametype == GAME_DEATHMATCH) { Sbar_DeathmatchOverlay (); return; } GL_SetCanvas (CANVAS_MENU); //johnfitz pic = Draw_CachePic ("gfx/complete.lmp"); Draw_Pic (64, 24, pic); pic = Draw_CachePic ("gfx/inter.lmp"); Draw_Pic (0, 56, pic); dig = cl.completed_time/60; Sbar_IntermissionNumber (152, 64, dig, 3, 0); //johnfitz -- was 160 num = cl.completed_time - dig*60; Draw_Pic (224,64,sb_colon); //johnfitz -- was 234 Draw_Pic (240,64,sb_nums[0][num/10]); //johnfitz -- was 246 Draw_Pic (264,64,sb_nums[0][num%10]); //johnfitz -- was 266 Sbar_IntermissionNumber (152, 104, cl.stats[STAT_SECRETS], 3, 0); //johnfitz -- was 160 Draw_Pic (224,104,sb_slash); //johnfitz -- was 232 Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0); //johnfitz -- was 248 Sbar_IntermissionNumber (152, 144, cl.stats[STAT_MONSTERS], 3, 0); //johnfitz -- was 160 Draw_Pic (224,144,sb_slash); //johnfitz -- was 232 Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0); //johnfitz -- was 248 } /* ================== Sbar_FinaleOverlay ================== */ void Sbar_FinaleOverlay (void) { qpic_t *pic; GL_SetCanvas (CANVAS_MENU); //johnfitz pic = Draw_CachePic ("gfx/finale.lmp"); Draw_Pic ( (320 - pic->width)/2, 16, pic); //johnfitz -- stretched menus } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_warp.c�������������������������������������������������������������������0000644�0000000�0000000�00000014324�12456331261�015325� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //gl_warp.c -- warping animation support #include "quakedef.h" extern cvar_t r_drawflat; cvar_t r_oldwater = {"r_oldwater", "0", CVAR_ARCHIVE}; cvar_t r_waterquality = {"r_waterquality", "8", CVAR_NONE}; cvar_t r_waterwarp = {"r_waterwarp", "1", CVAR_NONE}; int gl_warpimagesize; float load_subdivide_size; //johnfitz -- remember what subdivide_size value was when this map was loaded float turbsin[] = { #include "gl_warp_sin.h" }; #define WARPCALC(s,t) ((s + turbsin[(int)((t*2)+(cl.time*(128.0/M_PI))) & 255]) * (1.0/64)) //johnfitz -- correct warp #define WARPCALC2(s,t) ((s + turbsin[(int)((t*0.125+cl.time)*(128.0/M_PI)) & 255]) * (1.0/64)) //johnfitz -- old warp //============================================================================== // // OLD-STYLE WATER // //============================================================================== extern qmodel_t *loadmodel; msurface_t *warpface; cvar_t gl_subdivide_size = {"gl_subdivide_size", "128", CVAR_ARCHIVE}; void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs) { int i, j; float *v; mins[0] = mins[1] = mins[2] = 9999; maxs[0] = maxs[1] = maxs[2] = -9999; v = verts; for (i=0 ; i<numverts ; i++) for (j=0 ; j<3 ; j++, v++) { if (*v < mins[j]) mins[j] = *v; if (*v > maxs[j]) maxs[j] = *v; } } void SubdividePolygon (int numverts, float *verts) { int i, j, k; vec3_t mins, maxs; float m; float *v; vec3_t front[64], back[64]; int f, b; float dist[64]; float frac; glpoly_t *poly; float s, t; if (numverts > 60) Sys_Error ("numverts = %i", numverts); BoundPoly (numverts, verts, mins, maxs); for (i=0 ; i<3 ; i++) { m = (mins[i] + maxs[i]) * 0.5; m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5); if (maxs[i] - m < 8) continue; if (m - mins[i] < 8) continue; // cut it v = verts + i; for (j=0 ; j<numverts ; j++, v+= 3) dist[j] = *v - m; // wrap cases dist[j] = dist[0]; v-=i; VectorCopy (verts, v); f = b = 0; v = verts; for (j=0 ; j<numverts ; j++, v+= 3) { if (dist[j] >= 0) { VectorCopy (v, front[f]); f++; } if (dist[j] <= 0) { VectorCopy (v, back[b]); b++; } if (dist[j] == 0 || dist[j+1] == 0) continue; if ( (dist[j] > 0) != (dist[j+1] > 0) ) { // clip point frac = dist[j] / (dist[j] - dist[j+1]); for (k=0 ; k<3 ; k++) front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]); f++; b++; } } SubdividePolygon (f, front[0]); SubdividePolygon (b, back[0]); return; } poly = (glpoly_t *) Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float)); poly->next = warpface->polys->next; warpface->polys->next = poly; poly->numverts = numverts; for (i=0 ; i<numverts ; i++, verts+= 3) { VectorCopy (verts, poly->verts[i]); s = DotProduct (verts, warpface->texinfo->vecs[0]); t = DotProduct (verts, warpface->texinfo->vecs[1]); poly->verts[i][3] = s; poly->verts[i][4] = t; } } /* ================ GL_SubdivideSurface ================ */ void GL_SubdivideSurface (msurface_t *fa) { vec3_t verts[64]; int i; warpface = fa; //the first poly in the chain is the undivided poly for newwater rendering. //grab the verts from that. for (i=0; i<fa->polys->numverts; i++) VectorCopy (fa->polys->verts[i], verts[i]); SubdividePolygon (fa->polys->numverts, verts[0]); } /* ================ DrawWaterPoly -- johnfitz ================ */ void DrawWaterPoly (glpoly_t *p) { float *v; int i; if (load_subdivide_size > 48) { glBegin (GL_POLYGON); v = p->verts[0]; for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE) { glTexCoord2f (WARPCALC2(v[3],v[4]), WARPCALC2(v[4],v[3])); glVertex3fv (v); } glEnd (); } else { glBegin (GL_POLYGON); v = p->verts[0]; for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE) { glTexCoord2f (WARPCALC(v[3],v[4]), WARPCALC(v[4],v[3])); glVertex3fv (v); } glEnd (); } } //============================================================================== // // RENDER-TO-FRAMEBUFFER WATER // //============================================================================== /* ============= R_UpdateWarpTextures -- johnfitz -- each frame, update warping textures ============= */ void R_UpdateWarpTextures (void) { texture_t *tx; int i; float x, y, x2, warptess; if (r_oldwater.value || cl.paused || r_drawflat_cheatsafe || r_lightmap_cheatsafe) return; warptess = 128.0/CLAMP (3.0, floor(r_waterquality.value), 64.0); for (i=0; i<cl.worldmodel->numtextures; i++) { if (!(tx = cl.worldmodel->textures[i])) continue; if (!tx->update_warp) continue; //render warp GL_SetCanvas (CANVAS_WARPIMAGE); GL_Bind (tx->gltexture); for (x=0.0; x<128.0; x=x2) { x2 = x + warptess; glBegin (GL_TRIANGLE_STRIP); for (y=0.0; y<128.01; y+=warptess) // .01 for rounding errors { glTexCoord2f (WARPCALC(x,y), WARPCALC(y,x)); glVertex2f (x,y); glTexCoord2f (WARPCALC(x2,y), WARPCALC(y,x2)); glVertex2f (x2,y); } glEnd(); } //copy to texture GL_Bind (tx->warpimage); glCopyTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, glx, gly+glheight-gl_warpimagesize, gl_warpimagesize, gl_warpimagesize); tx->update_warp = false; } //if warp render went down into sbar territory, we need to be sure to refresh it next frame if (gl_warpimagesize + sb_lines > glheight) Sbar_Changed (); //if viewsize is less than 100, we need to redraw the frame around the viewport scr_tileclear_updates = 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_sky.c��������������������������������������������������������������������0000644�0000000�0000000�00000052250�12555253135�015165� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //gl_sky.c #include "quakedef.h" #define MAX_CLIP_VERTS 64 float Fog_GetDensity(void); float *Fog_GetColor(void); extern qmodel_t *loadmodel; extern int rs_skypolys; //for r_speeds readout extern int rs_skypasses; //for r_speeds readout float skyflatcolor[3]; float skymins[2][6], skymaxs[2][6]; char skybox_name[32] = ""; //name of current skybox, or "" if no skybox gltexture_t *skybox_textures[6]; gltexture_t *solidskytexture, *alphaskytexture; extern cvar_t gl_farclip; cvar_t r_fastsky = {"r_fastsky", "0", CVAR_NONE}; cvar_t r_sky_quality = {"r_sky_quality", "12", CVAR_NONE}; cvar_t r_skyalpha = {"r_skyalpha", "1", CVAR_NONE}; cvar_t r_skyfog = {"r_skyfog","0.5",CVAR_NONE}; int skytexorder[6] = {0,2,1,3,4,5}; //for skybox vec3_t skyclip[6] = { {1,1,0}, {1,-1,0}, {0,-1,1}, {0,1,1}, {1,0,1}, {-1,0,1} }; int st_to_vec[6][3] = { {3,-1,2}, {-3,1,2}, {1,3,2}, {-1,-3,2}, {-2,-1,3}, // straight up {2,-1,-3} // straight down }; int vec_to_st[6][3] = { {-2,3,1}, {2,3,-1}, {1,3,2}, {-1,3,-2}, {-2,-1,3}, {-2,1,-3} }; float skyfog; // ericw //============================================================================== // // INIT // //============================================================================== /* ============= Sky_LoadTexture A sky texture is 256*128, with the left side being a masked overlay ============== */ void Sky_LoadTexture (texture_t *mt) { char texturename[64]; int i, j, p, r, g, b, count; byte *src; static byte front_data[128*128]; //FIXME: Hunk_Alloc static byte back_data[128*128]; //FIXME: Hunk_Alloc unsigned *rgba; src = (byte *)mt + mt->offsets[0]; // extract back layer and upload for (i=0 ; i<128 ; i++) for (j=0 ; j<128 ; j++) back_data[(i*128) + j] = src[i*256 + j + 128]; q_snprintf(texturename, sizeof(texturename), "%s:%s_back", loadmodel->name, mt->name); solidskytexture = TexMgr_LoadImage (loadmodel, texturename, 128, 128, SRC_INDEXED, back_data, "", (src_offset_t)back_data, TEXPREF_NONE); // extract front layer and upload for (i=0 ; i<128 ; i++) for (j=0 ; j<128 ; j++) { front_data[(i*128) + j] = src[i*256 + j]; if (front_data[(i*128) + j] == 0) front_data[(i*128) + j] = 255; } q_snprintf(texturename, sizeof(texturename), "%s:%s_front", loadmodel->name, mt->name); alphaskytexture = TexMgr_LoadImage (loadmodel, texturename, 128, 128, SRC_INDEXED, front_data, "", (src_offset_t)front_data, TEXPREF_ALPHA); // calculate r_fastsky color based on average of all opaque foreground colors r = g = b = count = 0; for (i=0 ; i<128 ; i++) for (j=0 ; j<128 ; j++) { p = src[i*256 + j]; if (p != 0) { rgba = &d_8to24table[p]; r += ((byte *)rgba)[0]; g += ((byte *)rgba)[1]; b += ((byte *)rgba)[2]; count++; } } skyflatcolor[0] = (float)r/(count*255); skyflatcolor[1] = (float)g/(count*255); skyflatcolor[2] = (float)b/(count*255); } /* ================== Sky_LoadSkyBox ================== */ const char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; void Sky_LoadSkyBox (const char *name) { int i, mark, width, height; char filename[MAX_OSPATH]; byte *data; qboolean nonefound = true; if (strcmp(skybox_name, name) == 0) return; //no change //purge old textures for (i=0; i<6; i++) { if (skybox_textures[i] && skybox_textures[i] != notexture) TexMgr_FreeTexture (skybox_textures[i]); skybox_textures[i] = NULL; } //turn off skybox if sky is set to "" if (name[0] == 0) { skybox_name[0] = 0; return; } //load textures for (i=0; i<6; i++) { mark = Hunk_LowMark (); q_snprintf (filename, sizeof(filename), "gfx/env/%s%s", name, suf[i]); data = Image_LoadImage (filename, &width, &height); if (data) { skybox_textures[i] = TexMgr_LoadImage (cl.worldmodel, filename, width, height, SRC_RGBA, data, filename, 0, TEXPREF_NONE); nonefound = false; } else { Con_Printf ("Couldn't load %s\n", filename); skybox_textures[i] = notexture; } Hunk_FreeToLowMark (mark); } if (nonefound) // go back to scrolling sky if skybox is totally missing { for (i=0; i<6; i++) { if (skybox_textures[i] && skybox_textures[i] != notexture) TexMgr_FreeTexture (skybox_textures[i]); skybox_textures[i] = NULL; } skybox_name[0] = 0; return; } strcpy(skybox_name, name); } /* ================= Sky_NewMap ================= */ void Sky_NewMap (void) { char key[128], value[4096]; const char *data; int i; // // initially no sky // skybox_name[0] = 0; for (i=0; i<6; i++) skybox_textures[i] = NULL; skyfog = r_skyfog.value; // // read worldspawn (this is so ugly, and shouldn't it be done on the server?) // data = cl.worldmodel->entities; if (!data) return; //FIXME: how could this possibly ever happen? -- if there's no // worldspawn then the sever wouldn't send the loadmap message to the client data = COM_Parse(data); if (!data) //should never happen return; // error if (com_token[0] != '{') //should never happen return; // error while (1) { data = COM_Parse(data); if (!data) return; // error if (com_token[0] == '}') break; // end of worldspawn if (com_token[0] == '_') strcpy(key, com_token + 1); else strcpy(key, com_token); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; data = COM_Parse(data); if (!data) return; // error strcpy(value, com_token); if (!strcmp("sky", key)) Sky_LoadSkyBox(value); if (!strcmp("skyfog", key)) skyfog = atof(value); #if 1 //also accept non-standard keys else if (!strcmp("skyname", key)) //half-life Sky_LoadSkyBox(value); else if (!strcmp("qlsky", key)) //quake lives Sky_LoadSkyBox(value); #endif } } /* ================= Sky_SkyCommand_f ================= */ void Sky_SkyCommand_f (void) { switch (Cmd_Argc()) { case 1: Con_Printf("\"sky\" is \"%s\"\n", skybox_name); break; case 2: Sky_LoadSkyBox(Cmd_Argv(1)); break; default: Con_Printf("usage: sky <skyname>\n"); } } /* ==================== R_SetSkyfog_f -- ericw ==================== */ static void R_SetSkyfog_f (cvar_t *var) { // clear any skyfog setting from worldspawn skyfog = var->value; } /* ============= Sky_Init ============= */ void Sky_Init (void) { int i; Cvar_RegisterVariable (&r_fastsky); Cvar_RegisterVariable (&r_sky_quality); Cvar_RegisterVariable (&r_skyalpha); Cvar_RegisterVariable (&r_skyfog); Cvar_SetCallback (&r_skyfog, R_SetSkyfog_f); Cmd_AddCommand ("sky",Sky_SkyCommand_f); for (i=0; i<6; i++) skybox_textures[i] = NULL; } //============================================================================== // // PROCESS SKY SURFS // //============================================================================== /* ================= Sky_ProjectPoly update sky bounds ================= */ void Sky_ProjectPoly (int nump, vec3_t vecs) { int i,j; vec3_t v, av; float s, t, dv; int axis; float *vp; // decide which face it maps to VectorCopy (vec3_origin, v); for (i=0, vp=vecs ; i<nump ; i++, vp+=3) { VectorAdd (vp, v, v); } av[0] = fabs(v[0]); av[1] = fabs(v[1]); av[2] = fabs(v[2]); if (av[0] > av[1] && av[0] > av[2]) { if (v[0] < 0) axis = 1; else axis = 0; } else if (av[1] > av[2] && av[1] > av[0]) { if (v[1] < 0) axis = 3; else axis = 2; } else { if (v[2] < 0) axis = 5; else axis = 4; } // project new texture coords for (i=0 ; i<nump ; i++, vecs+=3) { j = vec_to_st[axis][2]; if (j > 0) dv = vecs[j - 1]; else dv = -vecs[-j - 1]; j = vec_to_st[axis][0]; if (j < 0) s = -vecs[-j -1] / dv; else s = vecs[j-1] / dv; j = vec_to_st[axis][1]; if (j < 0) t = -vecs[-j -1] / dv; else t = vecs[j-1] / dv; if (s < skymins[0][axis]) skymins[0][axis] = s; if (t < skymins[1][axis]) skymins[1][axis] = t; if (s > skymaxs[0][axis]) skymaxs[0][axis] = s; if (t > skymaxs[1][axis]) skymaxs[1][axis] = t; } } /* ================= Sky_ClipPoly ================= */ void Sky_ClipPoly (int nump, vec3_t vecs, int stage) { float *norm; float *v; qboolean front, back; float d, e; float dists[MAX_CLIP_VERTS]; int sides[MAX_CLIP_VERTS]; vec3_t newv[2][MAX_CLIP_VERTS]; int newc[2]; int i, j; if (nump > MAX_CLIP_VERTS-2) Sys_Error ("Sky_ClipPoly: MAX_CLIP_VERTS"); if (stage == 6) // fully clipped { Sky_ProjectPoly (nump, vecs); return; } front = back = false; norm = skyclip[stage]; for (i=0, v = vecs ; i<nump ; i++, v+=3) { d = DotProduct (v, norm); if (d > ON_EPSILON) { front = true; sides[i] = SIDE_FRONT; } else if (d < ON_EPSILON) { back = true; sides[i] = SIDE_BACK; } else sides[i] = SIDE_ON; dists[i] = d; } if (!front || !back) { // not clipped Sky_ClipPoly (nump, vecs, stage+1); return; } // clip it sides[i] = sides[0]; dists[i] = dists[0]; VectorCopy (vecs, (vecs+(i*3)) ); newc[0] = newc[1] = 0; for (i=0, v = vecs ; i<nump ; i++, v+=3) { switch (sides[i]) { case SIDE_FRONT: VectorCopy (v, newv[0][newc[0]]); newc[0]++; break; case SIDE_BACK: VectorCopy (v, newv[1][newc[1]]); newc[1]++; break; case SIDE_ON: VectorCopy (v, newv[0][newc[0]]); newc[0]++; VectorCopy (v, newv[1][newc[1]]); newc[1]++; break; } if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) continue; d = dists[i] / (dists[i] - dists[i+1]); for (j=0 ; j<3 ; j++) { e = v[j] + d*(v[j+3] - v[j]); newv[0][newc[0]][j] = e; newv[1][newc[1]][j] = e; } newc[0]++; newc[1]++; } // continue Sky_ClipPoly (newc[0], newv[0][0], stage+1); Sky_ClipPoly (newc[1], newv[1][0], stage+1); } /* ================ Sky_ProcessPoly ================ */ void Sky_ProcessPoly (glpoly_t *p) { int i; vec3_t verts[MAX_CLIP_VERTS]; //draw it DrawGLPoly(p); rs_brushpasses++; //update sky bounds if (!r_fastsky.value) { for (i=0 ; i<p->numverts ; i++) VectorSubtract (p->verts[i], r_origin, verts[i]); Sky_ClipPoly (p->numverts, verts[0], 0); } } /* ================ Sky_ProcessTextureChains -- handles sky polys in world model ================ */ void Sky_ProcessTextureChains (void) { int i; msurface_t *s; texture_t *t; if (!r_drawworld_cheatsafe) return; for (i=0 ; i<cl.worldmodel->numtextures ; i++) { t = cl.worldmodel->textures[i]; if (!t || !t->texturechains[chain_world] || !(t->texturechains[chain_world]->flags & SURF_DRAWSKY)) continue; for (s = t->texturechains[chain_world]; s; s = s->texturechain) if (!s->culled) Sky_ProcessPoly (s->polys); } } /* ================ Sky_ProcessEntities -- handles sky polys on brush models ================ */ void Sky_ProcessEntities (void) { entity_t *e; msurface_t *s; glpoly_t *p; int i,j,k,mark; float dot; qboolean rotated; vec3_t temp, forward, right, up; if (!r_drawentities.value) return; for (i=0 ; i<cl_numvisedicts ; i++) { e = cl_visedicts[i]; if (e->model->type != mod_brush) continue; if (R_CullModelForEntity(e)) continue; if (e->alpha == ENTALPHA_ZERO) continue; VectorSubtract (r_refdef.vieworg, e->origin, modelorg); if (e->angles[0] || e->angles[1] || e->angles[2]) { rotated = true; AngleVectors (e->angles, forward, right, up); VectorCopy (modelorg, temp); modelorg[0] = DotProduct (temp, forward); modelorg[1] = -DotProduct (temp, right); modelorg[2] = DotProduct (temp, up); } else rotated = false; s = &e->model->surfaces[e->model->firstmodelsurface]; for (j=0 ; j<e->model->nummodelsurfaces ; j++, s++) { if (s->flags & SURF_DRAWSKY) { dot = DotProduct (modelorg, s->plane->normal) - s->plane->dist; if (((s->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(s->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { //copy the polygon and translate manually, since Sky_ProcessPoly needs it to be in world space mark = Hunk_LowMark(); p = (glpoly_t *) Hunk_Alloc (sizeof(*s->polys)); //FIXME: don't allocate for each poly p->numverts = s->polys->numverts; for (k=0; k<p->numverts; k++) { if (rotated) { p->verts[k][0] = e->origin[0] + s->polys->verts[k][0] * forward[0] - s->polys->verts[k][1] * right[0] + s->polys->verts[k][2] * up[0]; p->verts[k][1] = e->origin[1] + s->polys->verts[k][0] * forward[1] - s->polys->verts[k][1] * right[1] + s->polys->verts[k][2] * up[1]; p->verts[k][2] = e->origin[2] + s->polys->verts[k][0] * forward[2] - s->polys->verts[k][1] * right[2] + s->polys->verts[k][2] * up[2]; } else VectorAdd(s->polys->verts[k], e->origin, p->verts[k]); } Sky_ProcessPoly (p); Hunk_FreeToLowMark (mark); } } } } } //============================================================================== // // RENDER SKYBOX // //============================================================================== /* ============== Sky_EmitSkyBoxVertex ============== */ void Sky_EmitSkyBoxVertex (float s, float t, int axis) { vec3_t v, b; int j, k; float w, h; b[0] = s * gl_farclip.value / sqrt(3.0); b[1] = t * gl_farclip.value / sqrt(3.0); b[2] = gl_farclip.value / sqrt(3.0); for (j=0 ; j<3 ; j++) { k = st_to_vec[axis][j]; if (k < 0) v[j] = -b[-k - 1]; else v[j] = b[k - 1]; v[j] += r_origin[j]; } // convert from range [-1,1] to [0,1] s = (s+1)*0.5; t = (t+1)*0.5; // avoid bilerp seam w = skybox_textures[skytexorder[axis]]->width; h = skybox_textures[skytexorder[axis]]->height; s = s * (w-1)/w + 0.5/w; t = t * (h-1)/h + 0.5/h; t = 1.0 - t; glTexCoord2f (s, t); glVertex3fv (v); } /* ============== Sky_DrawSkyBox FIXME: eliminate cracks by adding an extra vert on tjuncs ============== */ void Sky_DrawSkyBox (void) { int i; for (i=0 ; i<6 ; i++) { if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i]) continue; GL_Bind (skybox_textures[skytexorder[i]]); #if 1 //FIXME: this is to avoid tjunctions until i can do it the right way skymins[0][i] = -1; skymins[1][i] = -1; skymaxs[0][i] = 1; skymaxs[1][i] = 1; #endif glBegin (GL_QUADS); Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i); Sky_EmitSkyBoxVertex (skymins[0][i], skymaxs[1][i], i); Sky_EmitSkyBoxVertex (skymaxs[0][i], skymaxs[1][i], i); Sky_EmitSkyBoxVertex (skymaxs[0][i], skymins[1][i], i); glEnd (); rs_skypolys++; rs_skypasses++; if (Fog_GetDensity() > 0 && skyfog > 0) { float *c; c = Fog_GetColor(); glEnable (GL_BLEND); glDisable (GL_TEXTURE_2D); glColor4f (c[0],c[1],c[2], CLAMP(0.0,skyfog,1.0)); glBegin (GL_QUADS); Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i); Sky_EmitSkyBoxVertex (skymins[0][i], skymaxs[1][i], i); Sky_EmitSkyBoxVertex (skymaxs[0][i], skymaxs[1][i], i); Sky_EmitSkyBoxVertex (skymaxs[0][i], skymins[1][i], i); glEnd (); glColor3f (1, 1, 1); glEnable (GL_TEXTURE_2D); glDisable (GL_BLEND); rs_skypasses++; } } } //============================================================================== // // RENDER CLOUDS // //============================================================================== /* ============== Sky_SetBoxVert ============== */ void Sky_SetBoxVert (float s, float t, int axis, vec3_t v) { vec3_t b; int j, k; b[0] = s * gl_farclip.value / sqrt(3.0); b[1] = t * gl_farclip.value / sqrt(3.0); b[2] = gl_farclip.value / sqrt(3.0); for (j=0 ; j<3 ; j++) { k = st_to_vec[axis][j]; if (k < 0) v[j] = -b[-k - 1]; else v[j] = b[k - 1]; v[j] += r_origin[j]; } } /* ============= Sky_GetTexCoord ============= */ void Sky_GetTexCoord (vec3_t v, float speed, float *s, float *t) { vec3_t dir; float length, scroll; VectorSubtract (v, r_origin, dir); dir[2] *= 3; // flatten the sphere length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]; length = sqrt (length); length = 6*63/length; scroll = cl.time*speed; scroll -= (int)scroll & ~127; *s = (scroll + dir[0] * length) * (1.0/128); *t = (scroll + dir[1] * length) * (1.0/128); } /* =============== Sky_DrawFaceQuad =============== */ void Sky_DrawFaceQuad (glpoly_t *p) { float s, t; float *v; int i; if (gl_mtexable && r_skyalpha.value >= 1.0) { GL_Bind (solidskytexture); GL_EnableMultitexture(); GL_Bind (alphaskytexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glBegin (GL_QUADS); for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) { Sky_GetTexCoord (v, 8, &s, &t); GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, s, t); Sky_GetTexCoord (v, 16, &s, &t); GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, s, t); glVertex3fv (v); } glEnd (); GL_DisableMultitexture(); rs_skypolys++; rs_skypasses++; } else { GL_Bind (solidskytexture); if (r_skyalpha.value < 1.0) glColor3f (1, 1, 1); glBegin (GL_QUADS); for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) { Sky_GetTexCoord (v, 8, &s, &t); glTexCoord2f (s, t); glVertex3fv (v); } glEnd (); GL_Bind (alphaskytexture); glEnable (GL_BLEND); if (r_skyalpha.value < 1.0) glColor4f (1, 1, 1, r_skyalpha.value); glBegin (GL_QUADS); for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) { Sky_GetTexCoord (v, 16, &s, &t); glTexCoord2f (s, t); glVertex3fv (v); } glEnd (); glDisable (GL_BLEND); rs_skypolys++; rs_skypasses += 2; } if (Fog_GetDensity() > 0 && skyfog > 0) { float *c; c = Fog_GetColor(); glEnable (GL_BLEND); glDisable (GL_TEXTURE_2D); glColor4f (c[0],c[1],c[2], CLAMP(0.0,skyfog,1.0)); glBegin (GL_QUADS); for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) glVertex3fv (v); glEnd (); glColor3f (1, 1, 1); glEnable (GL_TEXTURE_2D); glDisable (GL_BLEND); rs_skypasses++; } } /* ============== Sky_DrawFace ============== */ void Sky_DrawFace (int axis) { glpoly_t *p; vec3_t verts[4]; int i, j, start; float di,qi,dj,qj; vec3_t vup, vright, temp, temp2; Sky_SetBoxVert(-1.0, -1.0, axis, verts[0]); Sky_SetBoxVert(-1.0, 1.0, axis, verts[1]); Sky_SetBoxVert(1.0, 1.0, axis, verts[2]); Sky_SetBoxVert(1.0, -1.0, axis, verts[3]); start = Hunk_LowMark (); p = (glpoly_t *) Hunk_Alloc(sizeof(glpoly_t)); VectorSubtract(verts[2],verts[3],vup); VectorSubtract(verts[2],verts[1],vright); di = q_max((int)r_sky_quality.value, 1); qi = 1.0 / di; dj = (axis < 4) ? di*2 : di; //subdivide vertically more than horizontally on skybox sides qj = 1.0 / dj; for (i=0; i<di; i++) { for (j=0; j<dj; j++) { if (i*qi < skymins[0][axis]/2+0.5 - qi || i*qi > skymaxs[0][axis]/2+0.5 || j*qj < skymins[1][axis]/2+0.5 - qj || j*qj > skymaxs[1][axis]/2+0.5) continue; //if (i&1 ^ j&1) continue; //checkerboard test VectorScale (vright, qi*i, temp); VectorScale (vup, qj*j, temp2); VectorAdd(temp,temp2,temp); VectorAdd(verts[0],temp,p->verts[0]); VectorScale (vup, qj, temp); VectorAdd (p->verts[0],temp,p->verts[1]); VectorScale (vright, qi, temp); VectorAdd (p->verts[1],temp,p->verts[2]); VectorAdd (p->verts[0],temp,p->verts[3]); Sky_DrawFaceQuad (p); } } Hunk_FreeToLowMark (start); } /* ============== Sky_DrawSkyLayers draws the old-style scrolling cloud layers ============== */ void Sky_DrawSkyLayers (void) { int i; if (r_skyalpha.value < 1.0) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); for (i=0 ; i<6 ; i++) if (skymins[0][i] < skymaxs[0][i] && skymins[1][i] < skymaxs[1][i]) Sky_DrawFace (i); if (r_skyalpha.value < 1.0) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } /* ============== Sky_DrawSky called once per frame before drawing anything else ============== */ void Sky_DrawSky (void) { int i; //in these special render modes, the sky faces are handled in the normal world/brush renderer if (r_drawflat_cheatsafe || r_lightmap_cheatsafe ) return; // // reset sky bounds // for (i=0 ; i<6 ; i++) { skymins[0][i] = skymins[1][i] = 9999; skymaxs[0][i] = skymaxs[1][i] = -9999; } // // process world and bmodels: draw flat-shaded sky surfs, and update skybounds // Fog_DisableGFog (); glDisable (GL_TEXTURE_2D); if (Fog_GetDensity() > 0) glColor3fv (Fog_GetColor()); else glColor3fv (skyflatcolor); Sky_ProcessTextureChains (); Sky_ProcessEntities (); glColor3f (1, 1, 1); glEnable (GL_TEXTURE_2D); // // render slow sky: cloud layers or skybox // if (!r_fastsky.value && !(Fog_GetDensity() > 0 && skyfog >= 1)) { glDepthFunc(GL_GEQUAL); glDepthMask(0); if (skybox_name[0]) Sky_DrawSkyBox (); else Sky_DrawSkyLayers(); glDepthMask(1); glDepthFunc(GL_LEQUAL); } Fog_EnableGFog (); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/progdefs.q1�����������������������������������������������������������������0000644�0000000�0000000�00000004627�11336354077�015615� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� /* file generated by qcc, do not modify */ typedef struct { int pad[28]; int self; int other; int world; float time; float frametime; float force_retouch; string_t mapname; float deathmatch; float coop; float teamplay; float serverflags; float total_secrets; float total_monsters; float found_secrets; float killed_monsters; float parm1; float parm2; float parm3; float parm4; float parm5; float parm6; float parm7; float parm8; float parm9; float parm10; float parm11; float parm12; float parm13; float parm14; float parm15; float parm16; vec3_t v_forward; vec3_t v_up; vec3_t v_right; float trace_allsolid; float trace_startsolid; float trace_fraction; vec3_t trace_endpos; vec3_t trace_plane_normal; float trace_plane_dist; int trace_ent; float trace_inopen; float trace_inwater; int msg_entity; func_t main; func_t StartFrame; func_t PlayerPreThink; func_t PlayerPostThink; func_t ClientKill; func_t ClientConnect; func_t PutClientInServer; func_t ClientDisconnect; func_t SetNewParms; func_t SetChangeParms; } globalvars_t; typedef struct { float modelindex; vec3_t absmin; vec3_t absmax; float ltime; float movetype; float solid; vec3_t origin; vec3_t oldorigin; vec3_t velocity; vec3_t angles; vec3_t avelocity; vec3_t punchangle; string_t classname; string_t model; float frame; float skin; float effects; vec3_t mins; vec3_t maxs; vec3_t size; func_t touch; func_t use; func_t think; func_t blocked; float nextthink; int groundentity; float health; float frags; float weapon; string_t weaponmodel; float weaponframe; float currentammo; float ammo_shells; float ammo_nails; float ammo_rockets; float ammo_cells; float items; float takedamage; int chain; float deadflag; vec3_t view_ofs; float button0; float button1; float button2; float impulse; float fixangle; vec3_t v_angle; float idealpitch; string_t netname; int enemy; float flags; float colormap; float team; float max_health; float teleport_time; float armortype; float armorvalue; float waterlevel; float watertype; float ideal_yaw; float yaw_speed; int aiment; int goalentity; float spawnflags; string_t target; string_t targetname; float dmg_take; float dmg_save; int dmg_inflictor; int owner; vec3_t movedir; string_t message; float sounds; string_t noise; string_t noise1; string_t noise2; string_t noise3; } entvars_t; #define PROGHEADER_CRC 5927 ���������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/strl_fn.h�������������������������������������������������������������������0000644�0000000�0000000�00000000503�11676323013�015337� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* header file for BSD strlcat and strlcpy */ #ifndef __STRLFUNCS_H #define __STRLFUNCS_H /* use our own copies of strlcpy and strlcat taken from OpenBSD */ extern size_t q_strlcpy (char *dst, const char *src, size_t size); extern size_t q_strlcat (char *dst, const char *src, size_t size); #endif /* __STRLFUNCS_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_screen.c�����������������������������������������������������������������0000644�0000000�0000000�00000056273�12537640371�015651� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // screen.c -- master for refresh, status bar, console, chat, notify, etc #include "quakedef.h" /* background clear rendering turtle/net/ram icons sbar centerprint / slow centerprint notify lines intermission / finale overlay loading plaque console menu required background clears required update regions syncronous draw mode or async One off screen buffer, with updates either copied or xblited Need to double buffer? async draw will require the refresh area to be cleared, because it will be xblited, but sync draw can just ignore it. sync draw CenterPrint () SlowPrint () Screen_Update (); Con_Printf (); net turn off messages option the refresh is allways rendered, unless the console is full screen console is: notify lines half full */ int glx, gly, glwidth, glheight; float scr_con_current; float scr_conlines; // lines of console to display //johnfitz -- new cvars cvar_t scr_menuscale = {"scr_menuscale", "1", CVAR_ARCHIVE}; cvar_t scr_sbarscale = {"scr_sbarscale", "1", CVAR_ARCHIVE}; cvar_t scr_sbaralpha = {"scr_sbaralpha", "0.75", CVAR_ARCHIVE}; cvar_t scr_conwidth = {"scr_conwidth", "0", CVAR_ARCHIVE}; cvar_t scr_conscale = {"scr_conscale", "1", CVAR_ARCHIVE}; cvar_t scr_crosshairscale = {"scr_crosshairscale", "1", CVAR_ARCHIVE}; cvar_t scr_showfps = {"scr_showfps", "0", CVAR_NONE}; cvar_t scr_clock = {"scr_clock", "0", CVAR_NONE}; //johnfitz cvar_t scr_viewsize = {"viewsize","100", CVAR_ARCHIVE}; cvar_t scr_fov = {"fov","90",CVAR_NONE}; // 10 - 170 cvar_t scr_fov_adapt = {"fov_adapt","1",CVAR_ARCHIVE}; cvar_t scr_conspeed = {"scr_conspeed","500",CVAR_ARCHIVE}; cvar_t scr_centertime = {"scr_centertime","2",CVAR_NONE}; cvar_t scr_showram = {"showram","1",CVAR_NONE}; cvar_t scr_showturtle = {"showturtle","0",CVAR_NONE}; cvar_t scr_showpause = {"showpause","1",CVAR_NONE}; cvar_t scr_printspeed = {"scr_printspeed","8",CVAR_NONE}; cvar_t gl_triplebuffer = {"gl_triplebuffer", "1", CVAR_ARCHIVE}; extern cvar_t crosshair; qboolean scr_initialized; // ready to draw qpic_t *scr_ram; qpic_t *scr_net; qpic_t *scr_turtle; int clearconsole; int clearnotify; vrect_t scr_vrect; qboolean scr_disabled_for_loading; qboolean scr_drawloading; float scr_disabled_time; int scr_tileclear_updates = 0; //johnfitz void SCR_ScreenShot_f (void); /* =============================================================================== CENTER PRINTING =============================================================================== */ char scr_centerstring[1024]; float scr_centertime_start; // for slow victory printing float scr_centertime_off; int scr_center_lines; int scr_erase_lines; int scr_erase_center; /* ============== SCR_CenterPrint Called for important messages that should stay in the center of the screen for a few moments ============== */ void SCR_CenterPrint (const char *str) //update centerprint data { strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1); scr_centertime_off = scr_centertime.value; scr_centertime_start = cl.time; // count the number of lines for centering scr_center_lines = 1; str = scr_centerstring; while (*str) { if (*str == '\n') scr_center_lines++; str++; } } void SCR_DrawCenterString (void) //actually do the drawing { char *start; int l; int j; int x, y; int remaining; GL_SetCanvas (CANVAS_MENU); //johnfitz // the finale prints the characters one at a time if (cl.intermission) remaining = scr_printspeed.value * (cl.time - scr_centertime_start); else remaining = 9999; scr_erase_center = 0; start = scr_centerstring; if (scr_center_lines <= 4) y = 200*0.35; //johnfitz -- 320x200 coordinate system else y = 48; if (crosshair.value) y -= 8; do { // scan the width of the line for (l=0 ; l<40 ; l++) if (start[l] == '\n' || !start[l]) break; x = (320 - l*8)/2; //johnfitz -- 320x200 coordinate system for (j=0 ; j<l ; j++, x+=8) { Draw_Character (x, y, start[j]); //johnfitz -- stretch overlays if (!remaining--) return; } y += 8; while (*start && *start != '\n') start++; if (!*start) break; start++; // skip the \n } while (1); } void SCR_CheckDrawCenterString (void) { if (scr_center_lines > scr_erase_lines) scr_erase_lines = scr_center_lines; scr_centertime_off -= host_frametime; if (scr_centertime_off <= 0 && !cl.intermission) return; if (key_dest != key_game) return; if (cl.paused) //johnfitz -- don't show centerprint during a pause return; SCR_DrawCenterString (); } //============================================================================= /* ==================== AdaptFovx Adapt a 4:3 horizontal FOV to the current screen size using the "Hor+" scaling: 2.0 * atan(width / height * 3.0 / 4.0 * tan(fov_x / 2.0)) ==================== */ float AdaptFovx (float fov_x, float width, float height) { float a, x; if (fov_x < 1 || fov_x > 179) Sys_Error ("Bad fov: %f", fov_x); if (!scr_fov_adapt.value) return fov_x; if ((x = height / width) == 0.75) return fov_x; a = atan(0.75 / x * tan(fov_x / 360 * M_PI)); a = a * 360 / M_PI; return a; } /* ==================== CalcFovy ==================== */ float CalcFovy (float fov_x, float width, float height) { float a, x; if (fov_x < 1 || fov_x > 179) Sys_Error ("Bad fov: %f", fov_x); x = width / tan(fov_x / 360 * M_PI); a = atan(height / x); a = a * 360 / M_PI; return a; } /* ================= SCR_CalcRefdef Must be called whenever vid changes Internal use only ================= */ static void SCR_CalcRefdef (void) { float size, scale; //johnfitz -- scale // force the status bar to redraw Sbar_Changed (); scr_tileclear_updates = 0; //johnfitz // bound viewsize if (scr_viewsize.value < 30) Cvar_SetQuick (&scr_viewsize, "30"); if (scr_viewsize.value > 120) Cvar_SetQuick (&scr_viewsize, "120"); // bound fov if (scr_fov.value < 10) Cvar_SetQuick (&scr_fov, "10"); if (scr_fov.value > 170) Cvar_SetQuick (&scr_fov, "170"); vid.recalc_refdef = 0; //johnfitz -- rewrote this section size = scr_viewsize.value; scale = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); if (size >= 120 || cl.intermission || scr_sbaralpha.value < 1) //johnfitz -- scr_sbaralpha.value sb_lines = 0; else if (size >= 110) sb_lines = 24 * scale; else sb_lines = 48 * scale; size = q_min(scr_viewsize.value, 100) / 100; //johnfitz //johnfitz -- rewrote this section r_refdef.vrect.width = q_max(glwidth * size, 96); //no smaller than 96, for icons r_refdef.vrect.height = q_min(glheight * size, glheight - sb_lines); //make room for sbar r_refdef.vrect.x = (glwidth - r_refdef.vrect.width)/2; r_refdef.vrect.y = (glheight - sb_lines - r_refdef.vrect.height)/2; //johnfitz r_refdef.fov_x = AdaptFovx(scr_fov.value, vid.width, vid.height); r_refdef.fov_y = CalcFovy (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); scr_vrect = r_refdef.vrect; } /* ================= SCR_SizeUp_f Keybinding command ================= */ void SCR_SizeUp_f (void) { Cvar_SetValueQuick (&scr_viewsize, scr_viewsize.value+10); } /* ================= SCR_SizeDown_f Keybinding command ================= */ void SCR_SizeDown_f (void) { Cvar_SetValueQuick (&scr_viewsize, scr_viewsize.value-10); } static void SCR_Callback_refdef (cvar_t *var) { vid.recalc_refdef = 1; } /* ================== SCR_Conwidth_f -- johnfitz -- called when scr_conwidth or scr_conscale changes ================== */ void SCR_Conwidth_f (cvar_t *var) { vid.recalc_refdef = 1; vid.conwidth = (scr_conwidth.value > 0) ? (int)scr_conwidth.value : (scr_conscale.value > 0) ? (int)(vid.width/scr_conscale.value) : vid.width; vid.conwidth = CLAMP (320, vid.conwidth, vid.width); vid.conwidth &= 0xFFFFFFF8; vid.conheight = vid.conwidth * vid.height / vid.width; } //============================================================================ /* ================== SCR_LoadPics -- johnfitz ================== */ void SCR_LoadPics (void) { scr_ram = Draw_PicFromWad ("ram"); scr_net = Draw_PicFromWad ("net"); scr_turtle = Draw_PicFromWad ("turtle"); } /* ================== SCR_Init ================== */ void SCR_Init (void) { //johnfitz -- new cvars Cvar_RegisterVariable (&scr_menuscale); Cvar_RegisterVariable (&scr_sbarscale); Cvar_SetCallback (&scr_sbaralpha, SCR_Callback_refdef); Cvar_RegisterVariable (&scr_sbaralpha); Cvar_SetCallback (&scr_conwidth, &SCR_Conwidth_f); Cvar_SetCallback (&scr_conscale, &SCR_Conwidth_f); Cvar_RegisterVariable (&scr_conwidth); Cvar_RegisterVariable (&scr_conscale); Cvar_RegisterVariable (&scr_crosshairscale); Cvar_RegisterVariable (&scr_showfps); Cvar_RegisterVariable (&scr_clock); //johnfitz Cvar_SetCallback (&scr_fov, SCR_Callback_refdef); Cvar_SetCallback (&scr_fov_adapt, SCR_Callback_refdef); Cvar_SetCallback (&scr_viewsize, SCR_Callback_refdef); Cvar_RegisterVariable (&scr_fov); Cvar_RegisterVariable (&scr_fov_adapt); Cvar_RegisterVariable (&scr_viewsize); Cvar_RegisterVariable (&scr_conspeed); Cvar_RegisterVariable (&scr_showram); Cvar_RegisterVariable (&scr_showturtle); Cvar_RegisterVariable (&scr_showpause); Cvar_RegisterVariable (&scr_centertime); Cvar_RegisterVariable (&scr_printspeed); Cvar_RegisterVariable (&gl_triplebuffer); Cmd_AddCommand ("screenshot",SCR_ScreenShot_f); Cmd_AddCommand ("sizeup",SCR_SizeUp_f); Cmd_AddCommand ("sizedown",SCR_SizeDown_f); SCR_LoadPics (); //johnfitz scr_initialized = true; } //============================================================================ /* ============== SCR_DrawFPS -- johnfitz ============== */ void SCR_DrawFPS (void) { static double oldtime = 0; static double lastfps = 0; static int oldframecount = 0; double elapsed_time; int frames; elapsed_time = realtime - oldtime; frames = r_framecount - oldframecount; if (elapsed_time < 0 || frames < 0) { oldtime = realtime; oldframecount = r_framecount; return; } // update value every 3/4 second if (elapsed_time > 0.75) { lastfps = frames / elapsed_time; oldtime = realtime; oldframecount = r_framecount; } if (scr_showfps.value) { char st[16]; int x, y; sprintf (st, "%4.0f fps", lastfps); x = 320 - (strlen(st)<<3); y = 200 - 8; if (scr_clock.value) y -= 8; //make room for clock GL_SetCanvas (CANVAS_BOTTOMRIGHT); Draw_String (x, y, st); scr_tileclear_updates = 0; } } /* ============== SCR_DrawClock -- johnfitz ============== */ void SCR_DrawClock (void) { char str[12]; if (scr_clock.value == 1) { int minutes, seconds; minutes = cl.time / 60; seconds = ((int)cl.time)%60; sprintf (str,"%i:%i%i", minutes, seconds/10, seconds%10); } else return; //draw it GL_SetCanvas (CANVAS_BOTTOMRIGHT); Draw_String (320 - (strlen(str)<<3), 200 - 8, str); scr_tileclear_updates = 0; } /* ============== SCR_DrawDevStats ============== */ void SCR_DrawDevStats (void) { char str[40]; int y = 25-9; //9=number of lines to print int x = 0; //margin if (!devstats.value) return; GL_SetCanvas (CANVAS_BOTTOMLEFT); Draw_Fill (x, y*8, 19*8, 9*8, 0, 0.5); //dark rectangle sprintf (str, "devstats |Curr Peak"); Draw_String (x, (y++)*8-x, str); sprintf (str, "---------+---------"); Draw_String (x, (y++)*8-x, str); sprintf (str, "Edicts |%4i %4i", dev_stats.edicts, dev_peakstats.edicts); Draw_String (x, (y++)*8-x, str); sprintf (str, "Packet |%4i %4i", dev_stats.packetsize, dev_peakstats.packetsize); Draw_String (x, (y++)*8-x, str); sprintf (str, "Visedicts|%4i %4i", dev_stats.visedicts, dev_peakstats.visedicts); Draw_String (x, (y++)*8-x, str); sprintf (str, "Efrags |%4i %4i", dev_stats.efrags, dev_peakstats.efrags); Draw_String (x, (y++)*8-x, str); sprintf (str, "Dlights |%4i %4i", dev_stats.dlights, dev_peakstats.dlights); Draw_String (x, (y++)*8-x, str); sprintf (str, "Beams |%4i %4i", dev_stats.beams, dev_peakstats.beams); Draw_String (x, (y++)*8-x, str); sprintf (str, "Tempents |%4i %4i", dev_stats.tempents, dev_peakstats.tempents); Draw_String (x, (y++)*8-x, str); } /* ============== SCR_DrawRam ============== */ void SCR_DrawRam (void) { if (!scr_showram.value) return; if (!r_cache_thrash) return; GL_SetCanvas (CANVAS_DEFAULT); //johnfitz Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram); } /* ============== SCR_DrawTurtle ============== */ void SCR_DrawTurtle (void) { static int count; if (!scr_showturtle.value) return; if (host_frametime < 0.1) { count = 0; return; } count++; if (count < 3) return; GL_SetCanvas (CANVAS_DEFAULT); //johnfitz Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); } /* ============== SCR_DrawNet ============== */ void SCR_DrawNet (void) { if (realtime - cl.last_received_message < 0.3) return; if (cls.demoplayback) return; GL_SetCanvas (CANVAS_DEFAULT); //johnfitz Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net); } /* ============== DrawPause ============== */ void SCR_DrawPause (void) { qpic_t *pic; if (!cl.paused) return; if (!scr_showpause.value) // turn off for screenshots return; GL_SetCanvas (CANVAS_MENU); //johnfitz pic = Draw_CachePic ("gfx/pause.lmp"); Draw_Pic ( (320 - pic->width)/2, (240 - 48 - pic->height)/2, pic); //johnfitz -- stretched menus scr_tileclear_updates = 0; //johnfitz } /* ============== SCR_DrawLoading ============== */ void SCR_DrawLoading (void) { qpic_t *pic; if (!scr_drawloading) return; GL_SetCanvas (CANVAS_MENU); //johnfitz pic = Draw_CachePic ("gfx/loading.lmp"); Draw_Pic ( (320 - pic->width)/2, (240 - 48 - pic->height)/2, pic); //johnfitz -- stretched menus scr_tileclear_updates = 0; //johnfitz } /* ============== SCR_DrawCrosshair -- johnfitz ============== */ void SCR_DrawCrosshair (void) { if (!crosshair.value) return; GL_SetCanvas (CANVAS_CROSSHAIR); Draw_Character (-4, -4, '+'); //0,0 is center of viewport } //============================================================================= /* ================== SCR_SetUpToDrawConsole ================== */ void SCR_SetUpToDrawConsole (void) { //johnfitz -- let's hack away the problem of slow console when host_timescale is <0 extern cvar_t host_timescale; float timescale; //johnfitz Con_CheckResize (); if (scr_drawloading) return; // never a console with loading plaque // decide on the height of the console con_forcedup = !cl.worldmodel || cls.signon != SIGNONS; if (con_forcedup) { scr_conlines = glheight; //full screen //johnfitz -- glheight instead of vid.height scr_con_current = scr_conlines; } else if (key_dest == key_console) scr_conlines = glheight/2; //half screen //johnfitz -- glheight instead of vid.height else scr_conlines = 0; //none visible timescale = (host_timescale.value > 0) ? host_timescale.value : 1; //johnfitz -- timescale if (scr_conlines < scr_con_current) { // ericw -- (glheight/600.0) factor makes conspeed resolution independent, using 800x600 as a baseline scr_con_current -= scr_conspeed.value*(glheight/600.0)*host_frametime/timescale; //johnfitz -- timescale if (scr_conlines > scr_con_current) scr_con_current = scr_conlines; } else if (scr_conlines > scr_con_current) { // ericw -- (glheight/600.0) scr_con_current += scr_conspeed.value*(glheight/600.0)*host_frametime/timescale; //johnfitz -- timescale if (scr_conlines < scr_con_current) scr_con_current = scr_conlines; } if (clearconsole++ < vid.numpages) Sbar_Changed (); if (!con_forcedup && scr_con_current) scr_tileclear_updates = 0; //johnfitz } /* ================== SCR_DrawConsole ================== */ void SCR_DrawConsole (void) { if (scr_con_current) { Con_DrawConsole (scr_con_current, true); clearconsole = 0; } else { if (key_dest == key_game || key_dest == key_message) Con_DrawNotify (); // only draw notify in game } } /* ============================================================================== SCREEN SHOTS ============================================================================== */ /* ================== SCR_ScreenShot_f -- johnfitz -- rewritten to use Image_WriteTGA ================== */ void SCR_ScreenShot_f (void) { byte *buffer; char tganame[16]; //johnfitz -- was [80] char checkname[MAX_OSPATH]; int i; // find a file name to save it to for (i=0; i<10000; i++) { q_snprintf (tganame, sizeof(tganame), "spasm%04i.tga", i); // "fitz%04i.tga" q_snprintf (checkname, sizeof(checkname), "%s/%s", com_gamedir, tganame); if (Sys_FileTime(checkname) == -1) break; // file doesn't exist } if (i == 10000) { Con_Printf ("SCR_ScreenShot_f: Couldn't find an unused filename\n"); return; } //get data if (!(buffer = (byte *) malloc(glwidth*glheight*3))) { Con_Printf ("SCR_ScreenShot_f: Couldn't allocate memory\n"); return; } glPixelStorei (GL_PACK_ALIGNMENT, 1);/* for widths that aren't a multiple of 4 */ glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer); // now write the file if (Image_WriteTGA (tganame, buffer, glwidth, glheight, 24, false)) Con_Printf ("Wrote %s\n", tganame); else Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); free (buffer); } //============================================================================= /* =============== SCR_BeginLoadingPlaque ================ */ void SCR_BeginLoadingPlaque (void) { S_StopAllSounds (true); if (cls.state != ca_connected) return; if (cls.signon != SIGNONS) return; // redraw with no console and the loading plaque Con_ClearNotify (); scr_centertime_off = 0; scr_con_current = 0; scr_drawloading = true; Sbar_Changed (); SCR_UpdateScreen (); scr_drawloading = false; scr_disabled_for_loading = true; scr_disabled_time = realtime; } /* =============== SCR_EndLoadingPlaque ================ */ void SCR_EndLoadingPlaque (void) { scr_disabled_for_loading = false; Con_ClearNotify (); } //============================================================================= const char *scr_notifystring; qboolean scr_drawdialog; void SCR_DrawNotifyString (void) { const char *start; int l; int j; int x, y; GL_SetCanvas (CANVAS_MENU); //johnfitz start = scr_notifystring; y = 200 * 0.35; //johnfitz -- stretched overlays do { // scan the width of the line for (l=0 ; l<40 ; l++) if (start[l] == '\n' || !start[l]) break; x = (320 - l*8)/2; //johnfitz -- stretched overlays for (j=0 ; j<l ; j++, x+=8) Draw_Character (x, y, start[j]); y += 8; while (*start && *start != '\n') start++; if (!*start) break; start++; // skip the \n } while (1); } /* ================== SCR_ModalMessage Displays a text string in the center of the screen and waits for a Y or N keypress. ================== */ int SCR_ModalMessage (const char *text, float timeout) //johnfitz -- timeout { double time1, time2; //johnfitz -- timeout int lastkey, lastchar; if (cls.state == ca_dedicated) return true; scr_notifystring = text; // draw a fresh screen scr_drawdialog = true; SCR_UpdateScreen (); scr_drawdialog = false; S_ClearBuffer (); // so dma doesn't loop current sound time1 = Sys_DoubleTime () + timeout; //johnfitz -- timeout time2 = 0.0f; //johnfitz -- timeout Key_BeginInputGrab (); do { Sys_SendKeyEvents (); Key_GetGrabbedInput (&lastkey, &lastchar); Sys_Sleep (16); if (timeout) time2 = Sys_DoubleTime (); //johnfitz -- zero timeout means wait forever. } while (lastchar != 'y' && lastchar != 'Y' && lastchar != 'n' && lastchar != 'N' && lastkey != K_ESCAPE && time2 <= time1); Key_EndInputGrab (); // SCR_UpdateScreen (); //johnfitz -- commented out //johnfitz -- timeout if (time2 > time1) return false; //johnfitz return (lastchar == 'y' || lastchar == 'Y'); } //============================================================================= //johnfitz -- deleted SCR_BringDownConsole /* ================== SCR_TileClear johnfitz -- modified to use glwidth/glheight instead of vid.width/vid.height also fixed the dimentions of right and top panels also added scr_tileclear_updates ================== */ void SCR_TileClear (void) { //ericw -- added check for glsl gamma. TODO: remove this ugly optimization? if (scr_tileclear_updates >= vid.numpages && !gl_clear.value && !(gl_glsl_gamma_able && vid_gamma.value != 1)) return; scr_tileclear_updates++; if (r_refdef.vrect.x > 0) { // left Draw_TileClear (0, 0, r_refdef.vrect.x, glheight - sb_lines); // right Draw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, 0, glwidth - r_refdef.vrect.x - r_refdef.vrect.width, glheight - sb_lines); } if (r_refdef.vrect.y > 0) { // top Draw_TileClear (r_refdef.vrect.x, 0, r_refdef.vrect.width, r_refdef.vrect.y); // bottom Draw_TileClear (r_refdef.vrect.x, r_refdef.vrect.y + r_refdef.vrect.height, r_refdef.vrect.width, glheight - r_refdef.vrect.y - r_refdef.vrect.height - sb_lines); } } /* ================== SCR_UpdateScreen This is called every frame, and can also be called explicitly to flush text to the screen. WARNING: be very careful calling this from elsewhere, because the refresh needs almost the entire 256k of stack space! ================== */ void SCR_UpdateScreen (void) { vid.numpages = (gl_triplebuffer.value) ? 3 : 2; if (scr_disabled_for_loading) { if (realtime - scr_disabled_time > 60) { scr_disabled_for_loading = false; Con_Printf ("load failed.\n"); } else return; } if (!scr_initialized || !con_initialized) return; // not initialized yet GL_BeginRendering (&glx, &gly, &glwidth, &glheight); // // determine size of refresh window // if (vid.recalc_refdef) SCR_CalcRefdef (); // // do 3D refresh drawing, and then update the screen // SCR_SetUpToDrawConsole (); V_RenderView (); GL_Set2D (); //FIXME: only call this when needed SCR_TileClear (); if (scr_drawdialog) //new game confirm { if (con_forcedup) Draw_ConsoleBackground (); else Sbar_Draw (); Draw_FadeScreen (); SCR_DrawNotifyString (); } else if (scr_drawloading) //loading { SCR_DrawLoading (); Sbar_Draw (); } else if (cl.intermission == 1 && key_dest == key_game) //end of level { Sbar_IntermissionOverlay (); } else if (cl.intermission == 2 && key_dest == key_game) //end of episode { Sbar_FinaleOverlay (); SCR_CheckDrawCenterString (); } else { SCR_DrawCrosshair (); //johnfitz SCR_DrawRam (); SCR_DrawNet (); SCR_DrawTurtle (); SCR_DrawPause (); SCR_CheckDrawCenterString (); Sbar_Draw (); SCR_DrawDevStats (); //johnfitz SCR_DrawFPS (); //johnfitz SCR_DrawClock (); //johnfitz SCR_DrawConsole (); M_Draw (); } V_UpdateBlend (); //johnfitz -- V_UpdatePalette cleaned up and renamed GLSLGamma_GammaCorrect (); GL_EndRendering (); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/server.h��������������������������������������������������������������������0000644�0000000�0000000�00000015045�12407762022�015205� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_SERVER_H #define _QUAKE_SERVER_H // server.h typedef struct { int maxclients; int maxclientslimit; struct client_s *clients; // [maxclients] int serverflags; // episode completion information qboolean changelevel_issued; // cleared when at SV_SpawnServer } server_static_t; //============================================================================= typedef enum {ss_loading, ss_active} server_state_t; typedef struct { qboolean active; // false if only a net client qboolean paused; qboolean loadgame; // handle connections specially double time; int lastcheck; // used by PF_checkclient double lastchecktime; char name[64]; // map name char modelname[64]; // maps/<name>.bsp, for model_precache[0] struct qmodel_s *worldmodel; const char *model_precache[MAX_MODELS]; // NULL terminated struct qmodel_s *models[MAX_MODELS]; const char *sound_precache[MAX_SOUNDS]; // NULL terminated const char *lightstyles[MAX_LIGHTSTYLES]; int num_edicts; int max_edicts; edict_t *edicts; // can NOT be array indexed, because // edict_t is variable sized, but can // be used to reference the world ent server_state_t state; // some actions are only valid during load sizebuf_t datagram; byte datagram_buf[MAX_DATAGRAM]; sizebuf_t reliable_datagram; // copied to all clients at end of frame byte reliable_datagram_buf[MAX_DATAGRAM]; sizebuf_t signon; byte signon_buf[MAX_MSGLEN-2]; //johnfitz -- was 8192, now uses MAX_MSGLEN unsigned protocol; //johnfitz } server_t; #define NUM_PING_TIMES 16 #define NUM_SPAWN_PARMS 16 typedef struct client_s { qboolean active; // false = client is free qboolean spawned; // false = don't send datagrams qboolean dropasap; // has been told to go to another level qboolean sendsignon; // only valid before spawned double last_message; // reliable messages must be sent // periodically struct qsocket_s *netconnection; // communications handle usercmd_t cmd; // movement vec3_t wishdir; // intended motion calced from cmd sizebuf_t message; // can be added to at any time, // copied and clear once per frame byte msgbuf[MAX_MSGLEN]; edict_t *edict; // EDICT_NUM(clientnum+1) char name[32]; // for printing to other people int colors; float ping_times[NUM_PING_TIMES]; int num_pings; // ping_times[num_pings%NUM_PING_TIMES] // spawn parms are carried from level to level float spawn_parms[NUM_SPAWN_PARMS]; // client known data for deltas int old_frags; } client_t; //============================================================================= // edict->movetype values #define MOVETYPE_NONE 0 // never moves #define MOVETYPE_ANGLENOCLIP 1 #define MOVETYPE_ANGLECLIP 2 #define MOVETYPE_WALK 3 // gravity #define MOVETYPE_STEP 4 // gravity, special edge handling #define MOVETYPE_FLY 5 #define MOVETYPE_TOSS 6 // gravity #define MOVETYPE_PUSH 7 // no clip to world, push and crush #define MOVETYPE_NOCLIP 8 #define MOVETYPE_FLYMISSILE 9 // extra size to monsters #define MOVETYPE_BOUNCE 10 // edict->solid values #define SOLID_NOT 0 // no interaction with other objects #define SOLID_TRIGGER 1 // touch on edge, but not blocking #define SOLID_BBOX 2 // touch on edge, block #define SOLID_SLIDEBOX 3 // touch on edge, but not an onground #define SOLID_BSP 4 // bsp clip, touch on edge, block // edict->deadflag values #define DEAD_NO 0 #define DEAD_DYING 1 #define DEAD_DEAD 2 #define DAMAGE_NO 0 #define DAMAGE_YES 1 #define DAMAGE_AIM 2 // edict->flags #define FL_FLY 1 #define FL_SWIM 2 //#define FL_GLIMPSE 4 #define FL_CONVEYOR 4 #define FL_CLIENT 8 #define FL_INWATER 16 #define FL_MONSTER 32 #define FL_GODMODE 64 #define FL_NOTARGET 128 #define FL_ITEM 256 #define FL_ONGROUND 512 #define FL_PARTIALGROUND 1024 // not all corners are valid #define FL_WATERJUMP 2048 // player jumping out of water #define FL_JUMPRELEASED 4096 // for jump debouncing // entity effects #define EF_BRIGHTFIELD 1 #define EF_MUZZLEFLASH 2 #define EF_BRIGHTLIGHT 4 #define EF_DIMLIGHT 8 #define SPAWNFLAG_NOT_EASY 256 #define SPAWNFLAG_NOT_MEDIUM 512 #define SPAWNFLAG_NOT_HARD 1024 #define SPAWNFLAG_NOT_DEATHMATCH 2048 //============================================================================ extern cvar_t teamplay; extern cvar_t skill; extern cvar_t deathmatch; extern cvar_t coop; extern cvar_t fraglimit; extern cvar_t timelimit; extern server_static_t svs; // persistant server info extern server_t sv; // local server extern client_t *host_client; extern edict_t *sv_player; //=========================================================== void SV_Init (void); void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count); void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume, float attenuation); void SV_DropClient (qboolean crash); void SV_SendClientMessages (void); void SV_ClearDatagram (void); int SV_ModelIndex (const char *name); void SV_SetIdealPitch (void); void SV_AddUpdates (void); void SV_ClientThink (void); void SV_AddClientToServer (struct qsocket_s *ret); void SV_ClientPrintf (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); void SV_BroadcastPrintf (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); void SV_Physics (void); qboolean SV_CheckBottom (edict_t *ent); qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink); void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg); void SV_MoveToGoal (void); void SV_CheckForNewClients (void); void SV_RunClients (void); void SV_SaveSpawnparms (); void SV_SpawnServer (const char *server); #endif /* _QUAKE_SERVER_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/anorms.h��������������������������������������������������������������������0000644�0000000�0000000�00000015443�12407762022�015200� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * anorms.h * * Copyright (C) 1996-1997 Id Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT 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. */ { -0.525731, 0.000000, 0.850651 }, { -0.442863, 0.238856, 0.864188 }, { -0.295242, 0.000000, 0.955423 }, { -0.309017, 0.500000, 0.809017 }, { -0.162460, 0.262866, 0.951056 }, { 0.000000, 0.000000, 1.000000 }, { 0.000000, 0.850651, 0.525731 }, { -0.147621, 0.716567, 0.681718 }, { 0.147621, 0.716567, 0.681718 }, { 0.000000, 0.525731, 0.850651 }, { 0.309017, 0.500000, 0.809017 }, { 0.525731, 0.000000, 0.850651 }, { 0.295242, 0.000000, 0.955423 }, { 0.442863, 0.238856, 0.864188 }, { 0.162460, 0.262866, 0.951056 }, { -0.681718, 0.147621, 0.716567 }, { -0.809017, 0.309017, 0.500000 }, { -0.587785, 0.425325, 0.688191 }, { -0.850651, 0.525731, 0.000000 }, { -0.864188, 0.442863, 0.238856 }, { -0.716567, 0.681718, 0.147621 }, { -0.688191, 0.587785, 0.425325 }, { -0.500000, 0.809017, 0.309017 }, { -0.238856, 0.864188, 0.442863 }, { -0.425325, 0.688191, 0.587785 }, { -0.716567, 0.681718, -0.147621 }, { -0.500000, 0.809017, -0.309017 }, { -0.525731, 0.850651, 0.000000 }, { 0.000000, 0.850651, -0.525731 }, { -0.238856, 0.864188, -0.442863 }, { 0.000000, 0.955423, -0.295242 }, { -0.262866, 0.951056, -0.162460 }, { 0.000000, 1.000000, 0.000000 }, { 0.000000, 0.955423, 0.295242 }, { -0.262866, 0.951056, 0.162460 }, { 0.238856, 0.864188, 0.442863 }, { 0.262866, 0.951056, 0.162460 }, { 0.500000, 0.809017, 0.309017 }, { 0.238856, 0.864188, -0.442863 }, { 0.262866, 0.951056, -0.162460 }, { 0.500000, 0.809017, -0.309017 }, { 0.850651, 0.525731, 0.000000 }, { 0.716567, 0.681718, 0.147621 }, { 0.716567, 0.681718, -0.147621 }, { 0.525731, 0.850651, 0.000000 }, { 0.425325, 0.688191, 0.587785 }, { 0.864188, 0.442863, 0.238856 }, { 0.688191, 0.587785, 0.425325 }, { 0.809017, 0.309017, 0.500000 }, { 0.681718, 0.147621, 0.716567 }, { 0.587785, 0.425325, 0.688191 }, { 0.955423, 0.295242, 0.000000 }, { 1.000000, 0.000000, 0.000000 }, { 0.951056, 0.162460, 0.262866 }, { 0.850651, -0.525731, 0.000000 }, { 0.955423, -0.295242, 0.000000 }, { 0.864188, -0.442863, 0.238856 }, { 0.951056, -0.162460, 0.262866 }, { 0.809017, -0.309017, 0.500000 }, { 0.681718, -0.147621, 0.716567 }, { 0.850651, 0.000000, 0.525731 }, { 0.864188, 0.442863, -0.238856 }, { 0.809017, 0.309017, -0.500000 }, { 0.951056, 0.162460, -0.262866 }, { 0.525731, 0.000000, -0.850651 }, { 0.681718, 0.147621, -0.716567 }, { 0.681718, -0.147621, -0.716567 }, { 0.850651, 0.000000, -0.525731 }, { 0.809017, -0.309017, -0.500000 }, { 0.864188, -0.442863, -0.238856 }, { 0.951056, -0.162460, -0.262866 }, { 0.147621, 0.716567, -0.681718 }, { 0.309017, 0.500000, -0.809017 }, { 0.425325, 0.688191, -0.587785 }, { 0.442863, 0.238856, -0.864188 }, { 0.587785, 0.425325, -0.688191 }, { 0.688191, 0.587785, -0.425325 }, { -0.147621, 0.716567, -0.681718 }, { -0.309017, 0.500000, -0.809017 }, { 0.000000, 0.525731, -0.850651 }, { -0.525731, 0.000000, -0.850651 }, { -0.442863, 0.238856, -0.864188 }, { -0.295242, 0.000000, -0.955423 }, { -0.162460, 0.262866, -0.951056 }, { 0.000000, 0.000000, -1.000000 }, { 0.295242, 0.000000, -0.955423 }, { 0.162460, 0.262866, -0.951056 }, { -0.442863, -0.238856, -0.864188 }, { -0.309017, -0.500000, -0.809017 }, { -0.162460, -0.262866, -0.951056 }, { 0.000000, -0.850651, -0.525731 }, { -0.147621, -0.716567, -0.681718 }, { 0.147621, -0.716567, -0.681718 }, { 0.000000, -0.525731, -0.850651 }, { 0.309017, -0.500000, -0.809017 }, { 0.442863, -0.238856, -0.864188 }, { 0.162460, -0.262866, -0.951056 }, { 0.238856, -0.864188, -0.442863 }, { 0.500000, -0.809017, -0.309017 }, { 0.425325, -0.688191, -0.587785 }, { 0.716567, -0.681718, -0.147621 }, { 0.688191, -0.587785, -0.425325 }, { 0.587785, -0.425325, -0.688191 }, { 0.000000, -0.955423, -0.295242 }, { 0.000000, -1.000000, 0.000000 }, { 0.262866, -0.951056, -0.162460 }, { 0.000000, -0.850651, 0.525731 }, { 0.000000, -0.955423, 0.295242 }, { 0.238856, -0.864188, 0.442863 }, { 0.262866, -0.951056, 0.162460 }, { 0.500000, -0.809017, 0.309017 }, { 0.716567, -0.681718, 0.147621 }, { 0.525731, -0.850651, 0.000000 }, { -0.238856, -0.864188, -0.442863 }, { -0.500000, -0.809017, -0.309017 }, { -0.262866, -0.951056, -0.162460 }, { -0.850651, -0.525731, 0.000000 }, { -0.716567, -0.681718, -0.147621 }, { -0.716567, -0.681718, 0.147621 }, { -0.525731, -0.850651, 0.000000 }, { -0.500000, -0.809017, 0.309017 }, { -0.238856, -0.864188, 0.442863 }, { -0.262866, -0.951056, 0.162460 }, { -0.864188, -0.442863, 0.238856 }, { -0.809017, -0.309017, 0.500000 }, { -0.688191, -0.587785, 0.425325 }, { -0.681718, -0.147621, 0.716567 }, { -0.442863, -0.238856, 0.864188 }, { -0.587785, -0.425325, 0.688191 }, { -0.309017, -0.500000, 0.809017 }, { -0.147621, -0.716567, 0.681718 }, { -0.425325, -0.688191, 0.587785 }, { -0.162460, -0.262866, 0.951056 }, { 0.442863, -0.238856, 0.864188 }, { 0.162460, -0.262866, 0.951056 }, { 0.309017, -0.500000, 0.809017 }, { 0.147621, -0.716567, 0.681718 }, { 0.000000, -0.525731, 0.850651 }, { 0.425325, -0.688191, 0.587785 }, { 0.587785, -0.425325, 0.688191 }, { 0.688191, -0.587785, 0.425325 }, { -0.955423, 0.295242, 0.000000 }, { -0.951056, 0.162460, 0.262866 }, { -1.000000, 0.000000, 0.000000 }, { -0.850651, 0.000000, 0.525731 }, { -0.955423, -0.295242, 0.000000 }, { -0.951056, -0.162460, 0.262866 }, { -0.864188, 0.442863, -0.238856 }, { -0.951056, 0.162460, -0.262866 }, { -0.809017, 0.309017, -0.500000 }, { -0.864188, -0.442863, -0.238856 }, { -0.951056, -0.162460, -0.262866 }, { -0.809017, -0.309017, -0.500000 }, { -0.681718, 0.147621, -0.716567 }, { -0.681718, -0.147621, -0.716567 }, { -0.850651, 0.000000, -0.525731 }, { -0.688191, 0.587785, -0.425325 }, { -0.587785, 0.425325, -0.688191 }, { -0.425325, 0.688191, -0.587785 }, { -0.425325, -0.688191, -0.587785 }, { -0.587785, -0.425325, -0.688191 }, { -0.688191, -0.587785, -0.425325 }, �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/Makefile.darwin�������������������������������������������������������������0000644�0000000�0000000�00000015745�12475157152�016467� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# GNU Makefile for compiling Mac OS X version of QuakeSpasm. # Usage: "make -f Makefile.darwin" # To cross-compile on Linux hosts, see the "build_cross_osx*.sh" scripts. # "make DEBUG=1" to build a debug client. # "make SDL_FRAMEWORK_PATH=/path/to/Frameworks" to specify the directory # containing SDL.framework and override the locally included versions. # "make DO_USERDIRS=1" to enable user directories support # Enable/Disable user directories support DO_USERDIRS=0 ### Enable/Disable SDL2 USE_SDL2=0 ### Enable/Disable codecs for streaming music support USE_CODEC_WAVE=1 USE_CODEC_FLAC=1 USE_CODEC_MP3=1 USE_CODEC_VORBIS=1 USE_CODEC_OPUS=1 # either mikmod (preferred) or modplug, not both USE_CODEC_MIKMOD=1 USE_CODEC_MODPLUG=0 USE_CODEC_UMX=1 # which library to use for mp3 decoding: mad or mpg123 MP3LIB=mad # which library to use for ogg decoding: vorbis or tremor VORBISLIB=vorbis # --------------------------- # Helper functions # --------------------------- check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi;) # --------------------------- HOST_OS := $(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]') MACH_TYPE= $(shell sh detect.sh arch) DEBUG ?= 0 # --------------------------- # build variables # --------------------------- CC ?= gcc LINKER = $(CC) LIPO ?= lipo STRIP ?= strip CPUFLAGS= LDFLAGS = DFLAGS ?= CFLAGS ?= -Wall # @rpath can be used when targeting 10.5+ USE_RPATH=0 # require 10.5 for 64 bit builds ifeq ($(MACH_TYPE),ppc64) CFLAGS +=-mmacosx-version-min=10.5 LDFLAGS +=-mmacosx-version-min=10.5 USE_RPATH=1 endif ifeq ($(USE_SDL2),1) # sdl2 needs targetting 10.5+ ifeq ($(MACH_TYPE),x86) CFLAGS +=-mmacosx-version-min=10.5 LDFLAGS +=-mmacosx-version-min=10.5 USE_RPATH=1 endif endif ifeq ($(MACH_TYPE),x86_64) # require 10.6 for amd64 builds, not 10.5 (SDL's requirement.) # bundle1.o is needed for dyld_stub_binding_helper CFLAGS +=-mmacosx-version-min=10.6 LDFLAGS +=-mmacosx-version-min=10.6 -Wl,-lbundle1.o USE_RPATH=1 endif CFLAGS += $(CPUFLAGS) ifeq ($(USE_RPATH),1) LDFLAGS+=-Wl,-rpath,@executable_path/../Frameworks endif ifneq ($(DEBUG),0) DFLAGS += -DDEBUG CFLAGS += -g do_strip= else DFLAGS += -DNDEBUG CFLAGS += -O2 CFLAGS += $(call check_gcc,-fweb,) CFLAGS += $(call check_gcc,-frename-registers,) cmd_strip=$(STRIP) $(1) define do_strip $(call cmd_strip,$(1)); endef endif ifeq ($(DO_USERDIRS),1) CFLAGS += -DDO_USERDIRS=1 endif ifeq ($(USE_SDL2),1) CFLAGS += -DUSE_SDL2 endif # not relying on sdl-config command and assuming # /Library/Frameworks/SDL.framework is available SDL_CFLAGS =-D_GNU_SOURCE=1 -D_THREAD_SAFE SDL_CFLAGS+=-DSDL_FRAMEWORK -DNO_SDL_CONFIG ifeq ($(USE_SDL2),1) SDL_FRAMEWORK_NAME = SDL2 else SDL_FRAMEWORK_NAME = SDL endif # default to our local SDL[2].framework for build SDL_FRAMEWORK_PATH ?=../MacOSX ifneq ($(SDL_FRAMEWORK_PATH),) SDL_LIBS +=-F$(SDL_FRAMEWORK_PATH) SDL_CFLAGS+=-F$(SDL_FRAMEWORK_PATH) endif SDL_LIBS +=-Wl,-framework,$(SDL_FRAMEWORK_NAME) -Wl,-framework,Cocoa NET_LIBS := ifneq ($(VORBISLIB),vorbis) ifneq ($(VORBISLIB),tremor) $(error Invalid VORBISLIB setting) endif endif ifneq ($(MP3LIB),mpg123) ifneq ($(MP3LIB),mad) $(error Invalid MP3LIB setting) endif endif ifeq ($(MP3LIB),mad) mp3_obj=snd_mp3.o lib_mp3dec=-lmad endif ifeq ($(MP3LIB),mpg123) mp3_obj=snd_mpg123.o lib_mp3dec=-lmpg123 endif ifeq ($(VORBISLIB),vorbis) cpp_vorbisdec= lib_vorbisdec=-lvorbisfile -lvorbis -logg endif ifeq ($(VORBISLIB),tremor) cpp_vorbisdec=-DVORBIS_USE_TREMOR lib_vorbisdec=-lvorbisidec -logg endif CODECLIBS := ifeq ($(USE_CODEC_WAVE),1) CFLAGS+= -DUSE_CODEC_WAVE endif ifeq ($(USE_CODEC_FLAC),1) CFLAGS+= -DUSE_CODEC_FLAC CODEC_INC = -I../MacOSX/codecs/include CODEC_LINK= -L../MacOSX/codecs/lib CODECLIBS+= -lFLAC endif ifeq ($(USE_CODEC_OPUS),1) CFLAGS+= -DUSE_CODEC_OPUS CODEC_INC = -I../MacOSX/codecs/include CODEC_LINK= -L../MacOSX/codecs/lib CODECLIBS+= -lopusfile -lopus -logg endif ifeq ($(USE_CODEC_VORBIS),1) CFLAGS+= -DUSE_CODEC_VORBIS $(cpp_vorbisdec) CODEC_INC = -I../MacOSX/codecs/include CODEC_LINK= -L../MacOSX/codecs/lib CODECLIBS+= $(lib_vorbisdec) endif ifeq ($(USE_CODEC_MP3),1) CFLAGS+= -DUSE_CODEC_MP3 CODEC_INC = -I../MacOSX/codecs/include CODEC_LINK= -L../MacOSX/codecs/lib CODECLIBS+= $(lib_mp3dec) endif ifeq ($(USE_CODEC_MIKMOD),1) CFLAGS+= -DUSE_CODEC_MIKMOD CODEC_INC = -I../MacOSX/codecs/include CODEC_LINK= -L../MacOSX/codecs/lib CODECLIBS+= -lmikmod endif ifeq ($(USE_CODEC_MODPLUG),1) CFLAGS+= -DUSE_CODEC_MODPLUG CODEC_INC = -I../MacOSX/codecs/include CODEC_LINK= -L../MacOSX/codecs/lib CODECLIBS+= -lmodplug endif ifeq ($(USE_CODEC_UMX),1) CFLAGS+= -DUSE_CODEC_UMX endif CFLAGS+= $(CODEC_INC) COMMON_LIBS:= -Wl,-framework,IOKit -Wl,-framework,OpenGL LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS) # --------------------------- # targets # --------------------------- .PHONY: clean debug release DEFAULT_TARGET := quakespasm # --------------------------- # rules # --------------------------- %.o: %.c $(CC) $(DFLAGS) -c $(CFLAGS) $(SDL_CFLAGS) -o $@ $^ %.o: %.m $(CC) $(DFLAGS) -c $(CFLAGS) $(SDL_CFLAGS) -o $@ $^ %.o: ../MacOSX/%.m $(CC) $(DFLAGS) -c -I../MacOSX $(CFLAGS) $(SDL_CFLAGS) -o $@ $^ # ---------------------------------------------------------------------------- # objects # ---------------------------------------------------------------------------- MUSIC_OBJS:= bgmusic.o \ snd_codec.o \ snd_flac.o \ snd_wave.o \ snd_vorbis.o \ snd_opus.o \ $(mp3_obj) \ snd_mikmod.o \ snd_modplug.o \ snd_umx.o COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS) SYSOBJ_SND := snd_sdl.o SYSOBJ_CDA := cd_sdl.o SYSOBJ_INPUT := in_sdl.o SYSOBJ_GL_VID:= gl_vidsdl.o SYSOBJ_NET := net_bsd.o net_udp.o SYSOBJ_LAUNCHER := AppController.o QuakeArgument.o QuakeArguments.o ScreenInfo.o SDLApplication.o SYSOBJ_SYS := pl_osx.o sys_sdl_unix.o SYSOBJ_MAIN:= main_sdl.o SDLMain.o GLOBJS = \ gl_refrag.o \ gl_rlight.o \ gl_rmain.o \ gl_fog.o \ gl_rmisc.o \ r_part.o \ r_world.o \ gl_screen.o \ gl_sky.o \ gl_warp.o \ $(SYSOBJ_GL_VID) \ gl_draw.o \ image.o \ gl_texmgr.o \ gl_mesh.o \ r_sprite.o \ r_alias.o \ r_brush.o \ gl_model.o OBJS := strlcat.o \ strlcpy.o \ $(GLOBJS) \ $(SYSOBJ_INPUT) \ $(COMOBJ_SND) \ $(SYSOBJ_SND) \ $(SYSOBJ_CDA) \ $(SYSOBJ_NET) \ net_dgrm.o \ net_loop.o \ net_main.o \ chase.o \ cl_demo.o \ cl_input.o \ cl_main.o \ cl_parse.o \ cl_tent.o \ console.o \ keys.o \ menu.o \ sbar.o \ view.o \ wad.o \ cmd.o \ common.o \ crc.o \ cvar.o \ cfgfile.o \ host.o \ host_cmd.o \ mathlib.o \ pr_cmds.o \ pr_edict.o \ pr_exec.o \ sv_main.o \ sv_move.o \ sv_phys.o \ sv_user.o \ world.o \ zone.o \ $(SYSOBJ_SYS) $(SYSOBJ_LAUNCHER) $(SYSOBJ_MAIN) # ------------------------ # darwin build rules # ------------------------ quakespasm: $(OBJS) $(LINKER) $(OBJS) $(LDFLAGS) $(LIBS) $(SDL_LIBS) -o $@ $(call do_strip,$@) release: quakespasm debug: $(error Use "make DEBUG=1") clean: rm -f $(shell find . \( -name '*~' -o -name '#*#' -o -name '*.o' -o -name '*.res' -o -name $(DEFAULT_TARGET) \) -print) ���������������������������quakespasm-0.91.0/Quake/bgmusic.c�������������������������������������������������������������������0000644�0000000�0000000�00000024156�12471320271�015323� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Background music handling for Quakespasm (adapted from uHexen2) * Handles streaming music as raw sound samples and runs the midi driver * * Copyright (C) 1999-2005 Id Software, Inc. * Copyright (C) 2010-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #include "quakedef.h" #include "snd_codec.h" #include "bgmusic.h" #define MUSIC_DIRNAME "music" qboolean bgmloop; cvar_t bgm_extmusic = {"bgm_extmusic", "1", CVAR_ARCHIVE}; static qboolean no_extmusic= false; static float old_volume = -1.0f; typedef enum _bgm_player { BGM_NONE = -1, BGM_MIDIDRV = 1, BGM_STREAMER } bgm_player_t; typedef struct music_handler_s { unsigned int type; /* 1U << n (see snd_codec.h) */ bgm_player_t player; /* Enumerated bgm player type */ int is_available; /* -1 means not present */ const char *ext; /* Expected file extension */ const char *dir; /* Where to look for music file */ struct music_handler_s *next; } music_handler_t; static music_handler_t wanted_handlers[] = { { CODECTYPE_VORBIS,BGM_STREAMER,-1, "ogg", MUSIC_DIRNAME, NULL }, { CODECTYPE_OPUS, BGM_STREAMER, -1, "opus", MUSIC_DIRNAME, NULL }, { CODECTYPE_MP3, BGM_STREAMER, -1, "mp3", MUSIC_DIRNAME, NULL }, { CODECTYPE_FLAC, BGM_STREAMER, -1, "flac", MUSIC_DIRNAME, NULL }, { CODECTYPE_WAV, BGM_STREAMER, -1, "wav", MUSIC_DIRNAME, NULL }, { CODECTYPE_MOD, BGM_STREAMER, -1, "it", MUSIC_DIRNAME, NULL }, { CODECTYPE_MOD, BGM_STREAMER, -1, "s3m", MUSIC_DIRNAME, NULL }, { CODECTYPE_MOD, BGM_STREAMER, -1, "xm", MUSIC_DIRNAME, NULL }, { CODECTYPE_MOD, BGM_STREAMER, -1, "mod", MUSIC_DIRNAME, NULL }, { CODECTYPE_UMX, BGM_STREAMER, -1, "umx", MUSIC_DIRNAME, NULL }, { CODECTYPE_NONE, BGM_NONE, -1, NULL, NULL, NULL } }; static music_handler_t *music_handlers = NULL; #define ANY_CODECTYPE 0xFFFFFFFF #define CDRIP_TYPES (CODECTYPE_VORBIS | CODECTYPE_MP3 | CODECTYPE_FLAC | CODECTYPE_WAV) #define CDRIPTYPE(x) (((x) & CDRIP_TYPES) != 0) static snd_stream_t *bgmstream = NULL; static void BGM_Play_f (void) { if (Cmd_Argc() == 2) { BGM_Play (Cmd_Argv(1)); } else { Con_Printf ("music <musicfile>\n"); return; } } static void BGM_Pause_f (void) { BGM_Pause (); } static void BGM_Resume_f (void) { BGM_Resume (); } static void BGM_Loop_f (void) { if (Cmd_Argc() == 2) { if (q_strcasecmp(Cmd_Argv(1), "0") == 0 || q_strcasecmp(Cmd_Argv(1),"off") == 0) bgmloop = false; else if (q_strcasecmp(Cmd_Argv(1), "1") == 0 || q_strcasecmp(Cmd_Argv(1),"on") == 0) bgmloop = true; else if (q_strcasecmp(Cmd_Argv(1),"toggle") == 0) bgmloop = !bgmloop; } if (bgmloop) Con_Printf("Music will be looped\n"); else Con_Printf("Music will not be looped\n"); } static void BGM_Stop_f (void) { BGM_Stop(); } qboolean BGM_Init (void) { music_handler_t *handlers = NULL; int i; Cvar_RegisterVariable(&bgm_extmusic); Cmd_AddCommand("music", BGM_Play_f); Cmd_AddCommand("music_pause", BGM_Pause_f); Cmd_AddCommand("music_resume", BGM_Resume_f); Cmd_AddCommand("music_loop", BGM_Loop_f); Cmd_AddCommand("music_stop", BGM_Stop_f); if (COM_CheckParm("-noextmusic") != 0) no_extmusic = true; bgmloop = true; for (i = 0; wanted_handlers[i].type != CODECTYPE_NONE; i++) { switch (wanted_handlers[i].player) { case BGM_MIDIDRV: /* not supported in quake */ break; case BGM_STREAMER: wanted_handlers[i].is_available = S_CodecIsAvailable(wanted_handlers[i].type); break; case BGM_NONE: default: break; } if (wanted_handlers[i].is_available != -1) { if (handlers) { handlers->next = &wanted_handlers[i]; handlers = handlers->next; } else { music_handlers = &wanted_handlers[i]; handlers = music_handlers; } } } return true; } void BGM_Shutdown (void) { BGM_Stop(); /* sever our connections to * midi_drv and snd_codec */ music_handlers = NULL; } static void BGM_Play_noext (const char *filename, unsigned int allowed_types) { char tmp[MAX_QPATH]; music_handler_t *handler; handler = music_handlers; while (handler) { if (! (handler->type & allowed_types)) { handler = handler->next; continue; } if (!handler->is_available) { handler = handler->next; continue; } q_snprintf(tmp, sizeof(tmp), "%s/%s.%s", handler->dir, filename, handler->ext); switch (handler->player) { case BGM_MIDIDRV: /* not supported in quake */ break; case BGM_STREAMER: bgmstream = S_CodecOpenStreamType(tmp, handler->type); if (bgmstream) return; /* success */ break; case BGM_NONE: default: break; } handler = handler->next; } Con_Printf("Couldn't handle music file %s\n", filename); } void BGM_Play (const char *filename) { char tmp[MAX_QPATH]; const char *ext; music_handler_t *handler; BGM_Stop(); if (music_handlers == NULL) return; if (!filename || !*filename) { Con_DPrintf("null music file name\n"); return; } ext = COM_FileGetExtension(filename); if (! *ext) /* try all things */ { BGM_Play_noext(filename, ANY_CODECTYPE); return; } handler = music_handlers; while (handler) { if (handler->is_available && !q_strcasecmp(ext, handler->ext)) break; handler = handler->next; } if (!handler) { Con_Printf("Unhandled extension for %s\n", filename); return; } q_snprintf(tmp, sizeof(tmp), "%s/%s", handler->dir, filename); switch (handler->player) { case BGM_MIDIDRV: /* not supported in quake */ break; case BGM_STREAMER: bgmstream = S_CodecOpenStreamType(tmp, handler->type); if (bgmstream) return; /* success */ break; case BGM_NONE: default: break; } Con_Printf("Couldn't handle music file %s\n", filename); } void BGM_PlayCDtrack (byte track, qboolean looping) { /* instead of searching by the order of music_handlers, do so by * the order of searchpath priority: the file from the searchpath * with the highest path_id is most likely from our own gamedir * itself. This way, if a mod has track02 as a *.mp3 file, which * is below *.ogg in the music_handler order, the mp3 will still * have priority over track02.ogg from, say, id1. */ char tmp[MAX_QPATH]; const char *ext; unsigned int path_id, prev_id, type; music_handler_t *handler; BGM_Stop(); if (CDAudio_Play(track, looping) == 0) return; /* success */ if (music_handlers == NULL) return; if (no_extmusic || !bgm_extmusic.value) return; prev_id = 0; type = 0; ext = NULL; handler = music_handlers; while (handler) { if (! handler->is_available) goto _next; if (! CDRIPTYPE(handler->type)) goto _next; q_snprintf(tmp, sizeof(tmp), "%s/track%02d.%s", MUSIC_DIRNAME, (int)track, handler->ext); if (! COM_FileExists(tmp, &path_id)) goto _next; if (path_id > prev_id) { prev_id = path_id; type = handler->type; ext = handler->ext; } _next: handler = handler->next; } if (ext == NULL) Con_Printf("Couldn't find a cdrip for track %d\n", (int)track); else { q_snprintf(tmp, sizeof(tmp), "%s/track%02d.%s", MUSIC_DIRNAME, (int)track, ext); bgmstream = S_CodecOpenStreamType(tmp, type); if (! bgmstream) Con_Printf("Couldn't handle music file %s\n", tmp); } } void BGM_Stop (void) { if (bgmstream) { bgmstream->status = STREAM_NONE; S_CodecCloseStream(bgmstream); bgmstream = NULL; s_rawend = 0; } } void BGM_Pause (void) { if (bgmstream) { if (bgmstream->status == STREAM_PLAY) bgmstream->status = STREAM_PAUSE; } } void BGM_Resume (void) { if (bgmstream) { if (bgmstream->status == STREAM_PAUSE) bgmstream->status = STREAM_PLAY; } } static void BGM_UpdateStream (void) { int res; /* Number of bytes read. */ int bufferSamples; int fileSamples; int fileBytes; byte raw[16384]; if (bgmstream->status != STREAM_PLAY) return; /* don't bother playing anything if musicvolume is 0 */ if (bgmvolume.value <= 0) return; /* see how many samples should be copied into the raw buffer */ if (s_rawend < paintedtime) s_rawend = paintedtime; while (s_rawend < paintedtime + MAX_RAW_SAMPLES) { bufferSamples = MAX_RAW_SAMPLES - (s_rawend - paintedtime); /* decide how much data needs to be read from the file */ fileSamples = bufferSamples * bgmstream->info.rate / shm->speed; if (!fileSamples) return; /* our max buffer size */ fileBytes = fileSamples * (bgmstream->info.width * bgmstream->info.channels); if (fileBytes > (int) sizeof(raw)) { fileBytes = (int) sizeof(raw); fileSamples = fileBytes / (bgmstream->info.width * bgmstream->info.channels); } /* Read */ res = S_CodecReadStream(bgmstream, fileBytes, raw); if (res < fileBytes) { fileBytes = res; fileSamples = res / (bgmstream->info.width * bgmstream->info.channels); } if (res > 0) /* data: add to raw buffer */ { S_RawSamples(fileSamples, bgmstream->info.rate, bgmstream->info.width, bgmstream->info.channels, raw, bgmvolume.value); } else if (res == 0) /* EOF */ { if (bgmloop) { res = S_CodecRewindStream(bgmstream); if (res != 0) { Con_Printf("Stream seek error (%i), stopping.\n", res); BGM_Stop(); return; } } else { BGM_Stop(); return; } } else /* res < 0: some read error */ { Con_Printf("Stream read error (%i), stopping.\n", res); BGM_Stop(); return; } } } void BGM_Update (void) { if (old_volume != bgmvolume.value) { if (bgmvolume.value < 0) Cvar_SetQuick (&bgmvolume, "0"); else if (bgmvolume.value > 1) Cvar_SetQuick (&bgmvolume, "1"); old_volume = bgmvolume.value; } if (bgmstream) BGM_UpdateStream (); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_mp3.h�������������������������������������������������������������������0000644�0000000�0000000�00000000331�11526305154�015232� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* MP3 decoding support using libmad or libmpg123. */ #if !defined(_SND_MP3_H_) #define _SND_MP3_H_ #if defined(USE_CODEC_MP3) extern snd_codec_t mp3_codec; #endif /* USE_CODEC_MP3 */ #endif /* ! _SND_MP3_H_ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/protocol.h������������������������������������������������������������������0000644�0000000�0000000�00000022043�12407762022�015534� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_PROTOCOL_H #define _QUAKE_PROTOCOL_H // protocol.h -- communications protocols #define PROTOCOL_NETQUAKE 15 //johnfitz -- standard quake protocol #define PROTOCOL_FITZQUAKE 666 //johnfitz -- added new protocol for fitzquake 0.85 // if the high bit of the servercmd is set, the low bits are fast update flags: #define U_MOREBITS (1<<0) #define U_ORIGIN1 (1<<1) #define U_ORIGIN2 (1<<2) #define U_ORIGIN3 (1<<3) #define U_ANGLE2 (1<<4) #define U_STEP (1<<5) //johnfitz -- was U_NOLERP, renamed since it's only used for MOVETYPE_STEP #define U_FRAME (1<<6) #define U_SIGNAL (1<<7) // just differentiates from other updates // svc_update can pass all of the fast update bits, plus more #define U_ANGLE1 (1<<8) #define U_ANGLE3 (1<<9) #define U_MODEL (1<<10) #define U_COLORMAP (1<<11) #define U_SKIN (1<<12) #define U_EFFECTS (1<<13) #define U_LONGENTITY (1<<14) //johnfitz -- PROTOCOL_FITZQUAKE -- new bits #define U_EXTEND1 (1<<15) #define U_ALPHA (1<<16) // 1 byte, uses ENTALPHA_ENCODE, not sent if equal to baseline #define U_FRAME2 (1<<17) // 1 byte, this is .frame & 0xFF00 (second byte) #define U_MODEL2 (1<<18) // 1 byte, this is .modelindex & 0xFF00 (second byte) #define U_LERPFINISH (1<<19) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 0.1, this is ent->v.nextthink - sv.time, used for lerping #define U_UNUSED20 (1<<20) #define U_UNUSED21 (1<<21) #define U_UNUSED22 (1<<22) #define U_EXTEND2 (1<<23) // another byte to follow, future expansion //johnfitz //johnfitz -- PROTOCOL_NEHAHRA transparency #define U_TRANS (1<<15) //johnfitz #define SU_VIEWHEIGHT (1<<0) #define SU_IDEALPITCH (1<<1) #define SU_PUNCH1 (1<<2) #define SU_PUNCH2 (1<<3) #define SU_PUNCH3 (1<<4) #define SU_VELOCITY1 (1<<5) #define SU_VELOCITY2 (1<<6) #define SU_VELOCITY3 (1<<7) #define SU_UNUSED8 (1<<8) //AVAILABLE BIT #define SU_ITEMS (1<<9) #define SU_ONGROUND (1<<10) // no data follows, the bit is it #define SU_INWATER (1<<11) // no data follows, the bit is it #define SU_WEAPONFRAME (1<<12) #define SU_ARMOR (1<<13) #define SU_WEAPON (1<<14) //johnfitz -- PROTOCOL_FITZQUAKE -- new bits #define SU_EXTEND1 (1<<15) // another byte to follow #define SU_WEAPON2 (1<<16) // 1 byte, this is .weaponmodel & 0xFF00 (second byte) #define SU_ARMOR2 (1<<17) // 1 byte, this is .armorvalue & 0xFF00 (second byte) #define SU_AMMO2 (1<<18) // 1 byte, this is .currentammo & 0xFF00 (second byte) #define SU_SHELLS2 (1<<19) // 1 byte, this is .ammo_shells & 0xFF00 (second byte) #define SU_NAILS2 (1<<20) // 1 byte, this is .ammo_nails & 0xFF00 (second byte) #define SU_ROCKETS2 (1<<21) // 1 byte, this is .ammo_rockets & 0xFF00 (second byte) #define SU_CELLS2 (1<<22) // 1 byte, this is .ammo_cells & 0xFF00 (second byte) #define SU_EXTEND2 (1<<23) // another byte to follow #define SU_WEAPONFRAME2 (1<<24) // 1 byte, this is .weaponframe & 0xFF00 (second byte) #define SU_WEAPONALPHA (1<<25) // 1 byte, this is alpha for weaponmodel, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT #define SU_UNUSED26 (1<<26) #define SU_UNUSED27 (1<<27) #define SU_UNUSED28 (1<<28) #define SU_UNUSED29 (1<<29) #define SU_UNUSED30 (1<<30) #define SU_EXTEND3 (1<<31) // another byte to follow, future expansion //johnfitz // a sound with no channel is a local only sound #define SND_VOLUME (1<<0) // a byte #define SND_ATTENUATION (1<<1) // a byte #define SND_LOOPING (1<<2) // a long #define DEFAULT_SOUND_PACKET_VOLUME 255 #define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 //johnfitz -- PROTOCOL_FITZQUAKE -- new bits #define SND_LARGEENTITY (1<<3) // a short + byte (instead of just a short) #define SND_LARGESOUND (1<<4) // a short soundindex (instead of a byte) //johnfitz //johnfitz -- PROTOCOL_FITZQUAKE -- flags for entity baseline messages #define B_LARGEMODEL (1<<0) // modelindex is short instead of byte #define B_LARGEFRAME (1<<1) // frame is short instead of byte #define B_ALPHA (1<<2) // 1 byte, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT //johnfitz //johnfitz -- PROTOCOL_FITZQUAKE -- alpha encoding #define ENTALPHA_DEFAULT 0 //entity's alpha is "default" (i.e. water obeys r_wateralpha) -- must be zero so zeroed out memory works #define ENTALPHA_ZERO 1 //entity is invisible (lowest possible alpha) #define ENTALPHA_ONE 255 //entity is fully opaque (highest possible alpha) #define ENTALPHA_ENCODE(a) (((a)==0)?ENTALPHA_DEFAULT:Q_rint(CLAMP(1,(a)*254.0f+1,255))) //server convert to byte to send to client #define ENTALPHA_DECODE(a) (((a)==ENTALPHA_DEFAULT)?1.0f:((float)(a)-1)/(254)) //client convert to float for rendering #define ENTALPHA_TOSAVE(a) (((a)==ENTALPHA_DEFAULT)?0.0f:(((a)==ENTALPHA_ZERO)?-1.0f:((float)(a)-1)/(254))) //server convert to float for savegame //johnfitz // defaults for clientinfo messages #define DEFAULT_VIEWHEIGHT 22 // game types sent by serverinfo // these determine which intermission screen plays #define GAME_COOP 0 #define GAME_DEATHMATCH 1 //================== // note that there are some defs.qc that mirror to these numbers // also related to svc_strings[] in cl_parse //================== // // server to client // #define svc_bad 0 #define svc_nop 1 #define svc_disconnect 2 #define svc_updatestat 3 // [byte] [long] #define svc_version 4 // [long] server version #define svc_setview 5 // [short] entity number #define svc_sound 6 // <see code> #define svc_time 7 // [float] server time #define svc_print 8 // [string] null terminated string #define svc_stufftext 9 // [string] stuffed into client's console buffer // the string should be \n terminated #define svc_setangle 10 // [angle3] set the view angle to this absolute value #define svc_serverinfo 11 // [long] version // [string] signon string // [string]..[0]model cache // [string]...[0]sounds cache #define svc_lightstyle 12 // [byte] [string] #define svc_updatename 13 // [byte] [string] #define svc_updatefrags 14 // [byte] [short] #define svc_clientdata 15 // <shortbits + data> #define svc_stopsound 16 // <see code> #define svc_updatecolors 17 // [byte] [byte] #define svc_particle 18 // [vec3] <variable> #define svc_damage 19 #define svc_spawnstatic 20 //#define svc_spawnbinary 21 #define svc_spawnbaseline 22 #define svc_temp_entity 23 #define svc_setpause 24 // [byte] on / off #define svc_signonnum 25 // [byte] used for the signon sequence #define svc_centerprint 26 // [string] to put in center of the screen #define svc_killedmonster 27 #define svc_foundsecret 28 #define svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten #define svc_intermission 30 // [string] music #define svc_finale 31 // [string] music [string] text #define svc_cdtrack 32 // [byte] track [byte] looptrack #define svc_sellscreen 33 #define svc_cutscene 34 //johnfitz -- PROTOCOL_FITZQUAKE -- new server messages #define svc_skybox 37 // [string] name #define svc_bf 40 #define svc_fog 41 // [byte] density [byte] red [byte] green [byte] blue [float] time #define svc_spawnbaseline2 42 // support for large modelindex, large framenum, alpha, using flags #define svc_spawnstatic2 43 // support for large modelindex, large framenum, alpha, using flags #define svc_spawnstaticsound2 44 // [coord3] [short] samp [byte] vol [byte] aten //johnfitz // // client to server // #define clc_bad 0 #define clc_nop 1 #define clc_disconnect 2 #define clc_move 3 // [usercmd_t] #define clc_stringcmd 4 // [string] message // // temp entity events // #define TE_SPIKE 0 #define TE_SUPERSPIKE 1 #define TE_GUNSHOT 2 #define TE_EXPLOSION 3 #define TE_TAREXPLOSION 4 #define TE_LIGHTNING1 5 #define TE_LIGHTNING2 6 #define TE_WIZSPIKE 7 #define TE_KNIGHTSPIKE 8 #define TE_LIGHTNING3 9 #define TE_LAVASPLASH 10 #define TE_TELEPORT 11 #define TE_EXPLOSION2 12 // PGM 01/21/97 #define TE_BEAM 13 // PGM 01/21/97 typedef struct { vec3_t origin; vec3_t angles; unsigned short modelindex; //johnfitz -- was int unsigned short frame; //johnfitz -- was int unsigned char colormap; //johnfitz -- was int unsigned char skin; //johnfitz -- was int unsigned char alpha; //johnfitz -- added int effects; } entity_state_t; typedef struct { vec3_t viewangles; // intended velocities float forwardmove; float sidemove; float upmove; } usercmd_t; #endif /* _QUAKE_PROTOCOL_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_draw.c�������������������������������������������������������������������0000644�0000000�0000000�00000044410�12407762022�015307� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // draw.c -- 2d drawing #include "quakedef.h" //extern unsigned char d_15to8table[65536]; //johnfitz -- never used cvar_t scr_conalpha = {"scr_conalpha", "0.5", CVAR_ARCHIVE}; //johnfitz qpic_t *draw_disc; qpic_t *draw_backtile; gltexture_t *char_texture; //johnfitz qpic_t *pic_ovr, *pic_ins; //johnfitz -- new cursor handling qpic_t *pic_nul; //johnfitz -- for missing gfx, don't crash //johnfitz -- new pics byte pic_ovr_data[8][8] = { {255,255,255,255,255,255,255,255}, {255, 15, 15, 15, 15, 15, 15,255}, {255, 15, 15, 15, 15, 15, 15, 2}, {255, 15, 15, 15, 15, 15, 15, 2}, {255, 15, 15, 15, 15, 15, 15, 2}, {255, 15, 15, 15, 15, 15, 15, 2}, {255, 15, 15, 15, 15, 15, 15, 2}, {255,255, 2, 2, 2, 2, 2, 2}, }; byte pic_ins_data[9][8] = { { 15, 15,255,255,255,255,255,255}, { 15, 15, 2,255,255,255,255,255}, { 15, 15, 2,255,255,255,255,255}, { 15, 15, 2,255,255,255,255,255}, { 15, 15, 2,255,255,255,255,255}, { 15, 15, 2,255,255,255,255,255}, { 15, 15, 2,255,255,255,255,255}, { 15, 15, 2,255,255,255,255,255}, {255, 2, 2,255,255,255,255,255}, }; byte pic_nul_data[8][8] = { {252,252,252,252, 0, 0, 0, 0}, {252,252,252,252, 0, 0, 0, 0}, {252,252,252,252, 0, 0, 0, 0}, {252,252,252,252, 0, 0, 0, 0}, { 0, 0, 0, 0,252,252,252,252}, { 0, 0, 0, 0,252,252,252,252}, { 0, 0, 0, 0,252,252,252,252}, { 0, 0, 0, 0,252,252,252,252}, }; byte pic_stipple_data[8][8] = { {255, 0, 0, 0,255, 0, 0, 0}, { 0, 0,255, 0, 0, 0,255, 0}, {255, 0, 0, 0,255, 0, 0, 0}, { 0, 0,255, 0, 0, 0,255, 0}, {255, 0, 0, 0,255, 0, 0, 0}, { 0, 0,255, 0, 0, 0,255, 0}, {255, 0, 0, 0,255, 0, 0, 0}, { 0, 0,255, 0, 0, 0,255, 0}, }; byte pic_crosshair_data[8][8] = { {255,255,255,255,255,255,255,255}, {255,255,255, 8, 9,255,255,255}, {255,255,255, 6, 8, 2,255,255}, {255, 6, 8, 8, 6, 8, 8,255}, {255,255, 2, 8, 8, 2, 2, 2}, {255,255,255, 7, 8, 2,255,255}, {255,255,255,255, 2, 2,255,255}, {255,255,255,255,255,255,255,255}, }; //johnfitz typedef struct { gltexture_t *gltexture; float sl, tl, sh, th; } glpic_t; canvastype currentcanvas = CANVAS_NONE; //johnfitz -- for GL_SetCanvas //============================================================================== // // PIC CACHING // //============================================================================== typedef struct cachepic_s { char name[MAX_QPATH]; qpic_t pic; byte padding[32]; // for appended glpic } cachepic_t; #define MAX_CACHED_PICS 128 cachepic_t menu_cachepics[MAX_CACHED_PICS]; int menu_numcachepics; byte menuplyr_pixels[4096]; // scrap allocation // Allocate all the little status bar obejcts into a single texture // to crutch up stupid hardware / drivers #define MAX_SCRAPS 2 #define BLOCK_WIDTH 256 #define BLOCK_HEIGHT 256 int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT]; //johnfitz -- removed *4 after BLOCK_HEIGHT qboolean scrap_dirty; gltexture_t *scrap_textures[MAX_SCRAPS]; //johnfitz /* ================ Scrap_AllocBlock returns an index into scrap_texnums[] and the position inside it ================ */ int Scrap_AllocBlock (int w, int h, int *x, int *y) { int i, j; int best, best2; int texnum; for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++) { best = BLOCK_HEIGHT; for (i=0 ; i<BLOCK_WIDTH-w ; i++) { best2 = 0; for (j=0 ; j<w ; j++) { if (scrap_allocated[texnum][i+j] >= best) break; if (scrap_allocated[texnum][i+j] > best2) best2 = scrap_allocated[texnum][i+j]; } if (j == w) { // this is a valid spot *x = i; *y = best = best2; } } if (best + h > BLOCK_HEIGHT) continue; for (i=0 ; i<w ; i++) scrap_allocated[texnum][*x + i] = best + h; return texnum; } Sys_Error ("Scrap_AllocBlock: full"); //johnfitz -- correct function name return 0; //johnfitz -- shut up compiler } /* ================ Scrap_Upload -- johnfitz -- now uses TexMgr ================ */ void Scrap_Upload (void) { char name[8]; int i; for (i=0; i<MAX_SCRAPS; i++) { sprintf (name, "scrap%i", i); scrap_textures[i] = TexMgr_LoadImage (NULL, name, BLOCK_WIDTH, BLOCK_HEIGHT, SRC_INDEXED, scrap_texels[i], "", (src_offset_t)scrap_texels[i], TEXPREF_ALPHA | TEXPREF_OVERWRITE | TEXPREF_NOPICMIP); } scrap_dirty = false; } /* ================ Draw_PicFromWad ================ */ qpic_t *Draw_PicFromWad (const char *name) { qpic_t *p; glpic_t gl; src_offset_t offset; //johnfitz p = (qpic_t *) W_GetLumpName (name); if (!p) return pic_nul; //johnfitz // load little ones into the scrap if (p->width < 64 && p->height < 64) { int x, y; int i, j, k; int texnum; texnum = Scrap_AllocBlock (p->width, p->height, &x, &y); scrap_dirty = true; k = 0; for (i=0 ; i<p->height ; i++) { for (j=0 ; j<p->width ; j++, k++) scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k]; } gl.gltexture = scrap_textures[texnum]; //johnfitz -- changed to an array //johnfitz -- no longer go from 0.01 to 0.99 gl.sl = x/(float)BLOCK_WIDTH; gl.sh = (x+p->width)/(float)BLOCK_WIDTH; gl.tl = y/(float)BLOCK_WIDTH; gl.th = (y+p->height)/(float)BLOCK_WIDTH; } else { char texturename[64]; //johnfitz q_snprintf (texturename, sizeof(texturename), "%s:%s", WADFILENAME, name); //johnfitz offset = (src_offset_t)p - (src_offset_t)wad_base + sizeof(int)*2; //johnfitz gl.gltexture = TexMgr_LoadImage (NULL, texturename, p->width, p->height, SRC_INDEXED, p->data, WADFILENAME, offset, TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr gl.sl = 0; gl.sh = (float)p->width/(float)TexMgr_PadConditional(p->width); //johnfitz gl.tl = 0; gl.th = (float)p->height/(float)TexMgr_PadConditional(p->height); //johnfitz } memcpy (p->data, &gl, sizeof(glpic_t)); return p; } /* ================ Draw_CachePic ================ */ qpic_t *Draw_CachePic (const char *path) { cachepic_t *pic; int i; qpic_t *dat; glpic_t gl; for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++) { if (!strcmp (path, pic->name)) return &pic->pic; } if (menu_numcachepics == MAX_CACHED_PICS) Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); menu_numcachepics++; strcpy (pic->name, path); // // load the pic from disk // dat = (qpic_t *)COM_LoadTempFile (path, NULL); if (!dat) Sys_Error ("Draw_CachePic: failed to load %s", path); SwapPic (dat); // HACK HACK HACK --- we need to keep the bytes for // the translatable player picture just for the menu // configuration dialog if (!strcmp (path, "gfx/menuplyr.lmp")) memcpy (menuplyr_pixels, dat->data, dat->width*dat->height); pic->pic.width = dat->width; pic->pic.height = dat->height; gl.gltexture = TexMgr_LoadImage (NULL, path, dat->width, dat->height, SRC_INDEXED, dat->data, path, sizeof(int)*2, TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr gl.sl = 0; gl.sh = (float)dat->width/(float)TexMgr_PadConditional(dat->width); //johnfitz gl.tl = 0; gl.th = (float)dat->height/(float)TexMgr_PadConditional(dat->height); //johnfitz memcpy (pic->pic.data, &gl, sizeof(glpic_t)); return &pic->pic; } /* ================ Draw_MakePic -- johnfitz -- generate pics from internal data ================ */ qpic_t *Draw_MakePic (const char *name, int width, int height, byte *data) { int flags = TEXPREF_NEAREST | TEXPREF_ALPHA | TEXPREF_PERSIST | TEXPREF_NOPICMIP | TEXPREF_PAD; qpic_t *pic; glpic_t gl; pic = (qpic_t *) Hunk_Alloc (sizeof(qpic_t) - 4 + sizeof (glpic_t)); pic->width = width; pic->height = height; gl.gltexture = TexMgr_LoadImage (NULL, name, width, height, SRC_INDEXED, data, "", (src_offset_t)data, flags); gl.sl = 0; gl.sh = (float)width/(float)TexMgr_PadConditional(width); gl.tl = 0; gl.th = (float)height/(float)TexMgr_PadConditional(height); memcpy (pic->data, &gl, sizeof(glpic_t)); return pic; } //============================================================================== // // INIT // //============================================================================== /* =============== Draw_LoadPics -- johnfitz =============== */ void Draw_LoadPics (void) { byte *data; src_offset_t offset; data = (byte *) W_GetLumpName ("conchars"); if (!data) Sys_Error ("Draw_LoadPics: couldn't load conchars"); offset = (src_offset_t)data - (src_offset_t)wad_base; char_texture = TexMgr_LoadImage (NULL, WADFILENAME":conchars", 128, 128, SRC_INDEXED, data, WADFILENAME, offset, TEXPREF_ALPHA | TEXPREF_NEAREST | TEXPREF_NOPICMIP | TEXPREF_CONCHARS); draw_disc = Draw_PicFromWad ("disc"); draw_backtile = Draw_PicFromWad ("backtile"); } /* =============== Draw_NewGame -- johnfitz =============== */ void Draw_NewGame (void) { cachepic_t *pic; int i; // empty scrap and reallocate gltextures memset(&scrap_allocated, 0, sizeof(scrap_allocated)); memset(&scrap_texels, 255, sizeof(scrap_texels)); Scrap_Upload (); //creates 2 empty gltextures // reload wad pics W_LoadWadFile (); //johnfitz -- filename is now hard-coded for honesty Draw_LoadPics (); SCR_LoadPics (); Sbar_LoadPics (); // empty lmp cache for (pic = menu_cachepics, i = 0; i < menu_numcachepics; pic++, i++) pic->name[0] = 0; menu_numcachepics = 0; } /* =============== Draw_Init -- johnfitz -- rewritten =============== */ void Draw_Init (void) { Cvar_RegisterVariable (&scr_conalpha); // clear scrap and allocate gltextures memset(&scrap_allocated, 0, sizeof(scrap_allocated)); memset(&scrap_texels, 255, sizeof(scrap_texels)); Scrap_Upload (); //creates 2 empty textures // create internal pics pic_ins = Draw_MakePic ("ins", 8, 9, &pic_ins_data[0][0]); pic_ovr = Draw_MakePic ("ovr", 8, 8, &pic_ovr_data[0][0]); pic_nul = Draw_MakePic ("nul", 8, 8, &pic_nul_data[0][0]); // load game pics Draw_LoadPics (); } //============================================================================== // // 2D DRAWING // //============================================================================== /* ================ Draw_CharacterQuad -- johnfitz -- seperate function to spit out verts ================ */ void Draw_CharacterQuad (int x, int y, char num) { int row, col; float frow, fcol, size; row = num>>4; col = num&15; frow = row*0.0625; fcol = col*0.0625; size = 0.0625; glTexCoord2f (fcol, frow); glVertex2f (x, y); glTexCoord2f (fcol + size, frow); glVertex2f (x+8, y); glTexCoord2f (fcol + size, frow + size); glVertex2f (x+8, y+8); glTexCoord2f (fcol, frow + size); glVertex2f (x, y+8); } /* ================ Draw_Character -- johnfitz -- modified to call Draw_CharacterQuad ================ */ void Draw_Character (int x, int y, int num) { if (y <= -8) return; // totally off screen num &= 255; if (num == 32) return; //don't waste verts on spaces GL_Bind (char_texture); glBegin (GL_QUADS); Draw_CharacterQuad (x, y, (char) num); glEnd (); } /* ================ Draw_String -- johnfitz -- modified to call Draw_CharacterQuad ================ */ void Draw_String (int x, int y, const char *str) { if (y <= -8) return; // totally off screen GL_Bind (char_texture); glBegin (GL_QUADS); while (*str) { if (*str != 32) //don't waste verts on spaces Draw_CharacterQuad (x, y, *str); str++; x += 8; } glEnd (); } /* ============= Draw_Pic -- johnfitz -- modified ============= */ void Draw_Pic (int x, int y, qpic_t *pic) { glpic_t *gl; if (scrap_dirty) Scrap_Upload (); gl = (glpic_t *)pic->data; GL_Bind (gl->gltexture); glBegin (GL_QUADS); glTexCoord2f (gl->sl, gl->tl); glVertex2f (x, y); glTexCoord2f (gl->sh, gl->tl); glVertex2f (x+pic->width, y); glTexCoord2f (gl->sh, gl->th); glVertex2f (x+pic->width, y+pic->height); glTexCoord2f (gl->sl, gl->th); glVertex2f (x, y+pic->height); glEnd (); } /* ============= Draw_TransPicTranslate -- johnfitz -- rewritten to use texmgr to do translation Only used for the player color selection menu ============= */ void Draw_TransPicTranslate (int x, int y, qpic_t *pic, int top, int bottom) { static int oldtop = -2; static int oldbottom = -2; if (top != oldtop || bottom != oldbottom) { glpic_t *p = (glpic_t *)pic->data; gltexture_t *glt = p->gltexture; oldtop = top; oldbottom = bottom; TexMgr_ReloadImage (glt, top, bottom); } Draw_Pic (x, y, pic); } /* ================ Draw_ConsoleBackground -- johnfitz -- rewritten ================ */ void Draw_ConsoleBackground (void) { qpic_t *pic; float alpha; pic = Draw_CachePic ("gfx/conback.lmp"); pic->width = vid.conwidth; pic->height = vid.conheight; alpha = (con_forcedup) ? 1.0 : scr_conalpha.value; GL_SetCanvas (CANVAS_CONSOLE); //in case this is called from weird places if (alpha > 0.0) { if (alpha < 1.0) { glEnable (GL_BLEND); glColor4f (1,1,1,alpha); glDisable (GL_ALPHA_TEST); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } Draw_Pic (0, 0, pic); if (alpha < 1.0) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glEnable (GL_ALPHA_TEST); glDisable (GL_BLEND); glColor4f (1,1,1,1); } } } /* ============= Draw_TileClear This repeats a 64*64 tile graphic to fill the screen around a sized down refresh window. ============= */ void Draw_TileClear (int x, int y, int w, int h) { glpic_t *gl; gl = (glpic_t *)draw_backtile->data; glColor3f (1,1,1); GL_Bind (gl->gltexture); glBegin (GL_QUADS); glTexCoord2f (x/64.0, y/64.0); glVertex2f (x, y); glTexCoord2f ( (x+w)/64.0, y/64.0); glVertex2f (x+w, y); glTexCoord2f ( (x+w)/64.0, (y+h)/64.0); glVertex2f (x+w, y+h); glTexCoord2f ( x/64.0, (y+h)/64.0 ); glVertex2f (x, y+h); glEnd (); } /* ============= Draw_Fill Fills a box of pixels with a single color ============= */ void Draw_Fill (int x, int y, int w, int h, int c, float alpha) //johnfitz -- added alpha { byte *pal = (byte *)d_8to24table; //johnfitz -- use d_8to24table instead of host_basepal glDisable (GL_TEXTURE_2D); glEnable (GL_BLEND); //johnfitz -- for alpha glDisable (GL_ALPHA_TEST); //johnfitz -- for alpha glColor4f (pal[c*4]/255.0, pal[c*4+1]/255.0, pal[c*4+2]/255.0, alpha); //johnfitz -- added alpha glBegin (GL_QUADS); glVertex2f (x,y); glVertex2f (x+w, y); glVertex2f (x+w, y+h); glVertex2f (x, y+h); glEnd (); glColor3f (1,1,1); glDisable (GL_BLEND); //johnfitz -- for alpha glEnable (GL_ALPHA_TEST); //johnfitz -- for alpha glEnable (GL_TEXTURE_2D); } /* ================ Draw_FadeScreen -- johnfitz -- revised ================ */ void Draw_FadeScreen (void) { GL_SetCanvas (CANVAS_DEFAULT); glEnable (GL_BLEND); glDisable (GL_ALPHA_TEST); glDisable (GL_TEXTURE_2D); glColor4f (0, 0, 0, 0.5); glBegin (GL_QUADS); glVertex2f (0,0); glVertex2f (glwidth, 0); glVertex2f (glwidth, glheight); glVertex2f (0, glheight); glEnd (); glColor4f (1,1,1,1); glEnable (GL_TEXTURE_2D); glEnable (GL_ALPHA_TEST); glDisable (GL_BLEND); Sbar_Changed(); } /* ================ GL_SetCanvas -- johnfitz -- support various canvas types ================ */ void GL_SetCanvas (canvastype newcanvas) { extern vrect_t scr_vrect; float s; int lines; if (newcanvas == currentcanvas) return; currentcanvas = newcanvas; glMatrixMode(GL_PROJECTION); glLoadIdentity (); switch(newcanvas) { case CANVAS_DEFAULT: glOrtho (0, glwidth, glheight, 0, -99999, 99999); glViewport (glx, gly, glwidth, glheight); break; case CANVAS_CONSOLE: lines = vid.conheight - (scr_con_current * vid.conheight / glheight); glOrtho (0, vid.conwidth, vid.conheight + lines, lines, -99999, 99999); glViewport (glx, gly, glwidth, glheight); break; case CANVAS_MENU: s = q_min((float)glwidth / 320.0, (float)glheight / 200.0); s = CLAMP (1.0, scr_menuscale.value, s); glOrtho (0, 320, 200, 0, -99999, 99999); glViewport (glx + (glwidth - 320*s) / 2, gly + (glheight - 200*s) / 2, 320*s, 200*s); break; case CANVAS_SBAR: s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); if (cl.gametype == GAME_DEATHMATCH) { glOrtho (0, glwidth / s, 48, 0, -99999, 99999); glViewport (glx, gly, glwidth, 48*s); } else { glOrtho (0, 320, 48, 0, -99999, 99999); glViewport (glx + (glwidth - 320*s) / 2, gly, 320*s, 48*s); } break; case CANVAS_WARPIMAGE: glOrtho (0, 128, 0, 128, -99999, 99999); glViewport (glx, gly+glheight-gl_warpimagesize, gl_warpimagesize, gl_warpimagesize); break; case CANVAS_CROSSHAIR: //0,0 is center of viewport s = CLAMP (1.0, scr_crosshairscale.value, 10.0); glOrtho (scr_vrect.width/-2/s, scr_vrect.width/2/s, scr_vrect.height/2/s, scr_vrect.height/-2/s, -99999, 99999); glViewport (scr_vrect.x, glheight - scr_vrect.y - scr_vrect.height, scr_vrect.width & ~1, scr_vrect.height & ~1); break; case CANVAS_BOTTOMLEFT: //used by devstats s = (float)glwidth/vid.conwidth; //use console scale glOrtho (0, 320, 200, 0, -99999, 99999); glViewport (glx, gly, 320*s, 200*s); break; case CANVAS_BOTTOMRIGHT: //used by fps/clock s = (float)glwidth/vid.conwidth; //use console scale glOrtho (0, 320, 200, 0, -99999, 99999); glViewport (glx+glwidth-320*s, gly, 320*s, 200*s); break; case CANVAS_TOPRIGHT: //used by disc s = 1; glOrtho (0, 320, 200, 0, -99999, 99999); glViewport (glx+glwidth-320*s, gly+glheight-200*s, 320*s, 200*s); break; default: Sys_Error ("GL_SetCanvas: bad canvas type"); } glMatrixMode(GL_MODELVIEW); glLoadIdentity (); } /* ================ GL_Set2D -- johnfitz -- rewritten ================ */ void GL_Set2D (void) { currentcanvas = CANVAS_INVALID; GL_SetCanvas (CANVAS_DEFAULT); glDisable (GL_DEPTH_TEST); glDisable (GL_CULL_FACE); glDisable (GL_BLEND); glEnable (GL_ALPHA_TEST); glColor4f (1,1,1,1); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cvar.h����������������������������������������������������������������������0000644�0000000�0000000�00000011615�12407762022�014631� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __CVAR_H__ #define __CVAR_H__ /* cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly in C code. it is sufficient to initialize a cvar_t with just the first two fields, or you can add a ,true flag for variables that you want saved to the configuration file when the game is quit: cvar_t r_draworder = {"r_draworder","1"}; cvar_t scr_screensize = {"screensize","1",true}; Cvars must be registered before use, or they will have a 0 value instead of the float interpretation of the string. Generally, all cvar_t declarations should be registered in the apropriate init function before any console commands are executed: Cvar_RegisterVariable (&host_framerate); C code usually just references a cvar in place: if ( r_draworder.value ) It could optionally ask for the value to be looked up for a string name: if (Cvar_VariableValue ("r_draworder")) Interpreted prog code can access cvars with the cvar(name) or cvar_set (name, value) internal functions: teamplay = cvar("teamplay"); cvar_set ("registered", "1"); The user can access cvars from the console in two ways: r_draworder prints the current value r_draworder 0 sets the current value to 0 Cvars are restricted from having the same names as commands to keep this interface from being ambiguous. */ #define CVAR_NONE 0 #define CVAR_ARCHIVE (1U << 0) // if set, causes it to be saved to config #define CVAR_NOTIFY (1U << 1) // changes will be broadcasted to all players (q1) #define CVAR_SERVERINFO (1U << 2) // added to serverinfo will be sent to clients (q1/net_dgrm.c and qwsv) #define CVAR_USERINFO (1U << 3) // added to userinfo, will be sent to server (qwcl) #define CVAR_CHANGED (1U << 4) #define CVAR_ROM (1U << 6) #define CVAR_LOCKED (1U << 8) // locked temporarily #define CVAR_REGISTERED (1U << 10) // the var is added to the list of variables #define CVAR_CALLBACK (1U << 16) // var has a callback typedef void (*cvarcallback_t) (struct cvar_s *); typedef struct cvar_s { const char *name; const char *string; unsigned int flags; float value; const char *default_string; //johnfitz -- remember defaults for reset function cvarcallback_t callback; struct cvar_s *next; } cvar_t; void Cvar_RegisterVariable (cvar_t *variable); // registers a cvar that already has the name, string, and optionally // the archive elements set. void Cvar_SetCallback (cvar_t *var, cvarcallback_t func); // set a callback function to the var void Cvar_Set (const char *var_name, const char *value); // equivelant to "<name> <variable>" typed at the console void Cvar_SetValue (const char *var_name, const float value); // expands value to a string and calls Cvar_Set void Cvar_SetROM (const char *var_name, const char *value); void Cvar_SetValueROM (const char *var_name, const float value); // sets a CVAR_ROM variable from within the engine void Cvar_SetQuick (cvar_t *var, const char *value); void Cvar_SetValueQuick (cvar_t *var, const float value); // these two accept a cvar pointer instead of a var name, // but are otherwise identical to the "non-Quick" versions. // the cvar MUST be registered. float Cvar_VariableValue (const char *var_name); // returns 0 if not defined or non numeric const char *Cvar_VariableString (const char *var_name); // returns an empty string if not defined qboolean Cvar_Command (void); // called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known // command. Returns true if the command was a variable reference that // was handled. (print or change) void Cvar_WriteVariables (FILE *f); // Writes lines containing "set variable value" for all variables // with the CVAR_ARCHIVE flag set cvar_t *Cvar_FindVar (const char *var_name); cvar_t *Cvar_FindVarAfter (const char *prev_name, unsigned int with_flags); void Cvar_LockVar (const char *var_name); void Cvar_UnlockVar (const char *var_name); void Cvar_UnlockAll (void); void Cvar_Init (void); const char *Cvar_CompleteVariable (const char *partial); // attempts to match a partial variable name for command line completion // returns NULL if nothing fits #endif /* __CVAR_H__ */ �������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/host.c����������������������������������������������������������������������0000644�0000000�0000000�00000051643�12644623706�014663� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // host.c -- coordinates spawning and killing of local servers #include "quakedef.h" #include "bgmusic.h" #include <setjmp.h> /* A server can allways be started, even if the system started out as a client to a remote system. A client can NOT be started if the system started as a dedicated server. Memory is cleared / released when a server or client begins, not when they end. */ quakeparms_t *host_parms; qboolean host_initialized; // true if into command execution double host_frametime; double realtime; // without any filtering or bounding double oldrealtime; // last frame run int host_framecount; int host_hunklevel; int minimum_memory; client_t *host_client; // current client jmp_buf host_abortserver; byte *host_colormap; cvar_t host_framerate = {"host_framerate","0",CVAR_NONE}; // set for slow motion cvar_t host_speeds = {"host_speeds","0",CVAR_NONE}; // set for running times cvar_t host_maxfps = {"host_maxfps", "72", CVAR_ARCHIVE}; //johnfitz cvar_t host_timescale = {"host_timescale", "0", CVAR_NONE}; //johnfitz cvar_t max_edicts = {"max_edicts", "8192", CVAR_NONE}; //johnfitz //ericw -- changed from 2048 to 8192, removed CVAR_ARCHIVE cvar_t sys_ticrate = {"sys_ticrate","0.05",CVAR_NONE}; // dedicated server cvar_t serverprofile = {"serverprofile","0",CVAR_NONE}; cvar_t fraglimit = {"fraglimit","0",CVAR_NOTIFY|CVAR_SERVERINFO}; cvar_t timelimit = {"timelimit","0",CVAR_NOTIFY|CVAR_SERVERINFO}; cvar_t teamplay = {"teamplay","0",CVAR_NOTIFY|CVAR_SERVERINFO}; cvar_t samelevel = {"samelevel","0",CVAR_NONE}; cvar_t noexit = {"noexit","0",CVAR_NOTIFY|CVAR_SERVERINFO}; cvar_t skill = {"skill","1",CVAR_NONE}; // 0 - 3 cvar_t deathmatch = {"deathmatch","0",CVAR_NONE}; // 0, 1, or 2 cvar_t coop = {"coop","0",CVAR_NONE}; // 0 or 1 cvar_t pausable = {"pausable","1",CVAR_NONE}; cvar_t developer = {"developer","0",CVAR_NONE}; cvar_t temp1 = {"temp1","0",CVAR_NONE}; cvar_t devstats = {"devstats","0",CVAR_NONE}; //johnfitz -- track developer statistics that vary every frame devstats_t dev_stats, dev_peakstats; overflowtimes_t dev_overflows; //this stores the last time overflow messages were displayed, not the last time overflows occured /* ================ Max_Edicts_f -- johnfitz ================ */ static void Max_Edicts_f (cvar_t *var) { //TODO: clamp it here? if (cls.state == ca_connected || sv.active) Con_Printf ("Changes to max_edicts will not take effect until the next time a map is loaded.\n"); } /* ================ Host_EndGame ================ */ void Host_EndGame (const char *message, ...) { va_list argptr; char string[1024]; va_start (argptr,message); q_vsnprintf (string, sizeof(string), message, argptr); va_end (argptr); Con_DPrintf ("Host_EndGame: %s\n",string); if (sv.active) Host_ShutdownServer (false); if (cls.state == ca_dedicated) Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit if (cls.demonum != -1) CL_NextDemo (); else CL_Disconnect (); longjmp (host_abortserver, 1); } /* ================ Host_Error This shuts down both the client and server ================ */ void Host_Error (const char *error, ...) { va_list argptr; char string[1024]; static qboolean inerror = false; if (inerror) Sys_Error ("Host_Error: recursively entered"); inerror = true; SCR_EndLoadingPlaque (); // reenable screen updates va_start (argptr,error); q_vsnprintf (string, sizeof(string), error, argptr); va_end (argptr); Con_Printf ("Host_Error: %s\n",string); if (sv.active) Host_ShutdownServer (false); if (cls.state == ca_dedicated) Sys_Error ("Host_Error: %s\n",string); // dedicated servers exit CL_Disconnect (); cls.demonum = -1; cl.intermission = 0; //johnfitz -- for errors during intermissions (changelevel with no map found, etc.) inerror = false; longjmp (host_abortserver, 1); } /* ================ Host_FindMaxClients ================ */ void Host_FindMaxClients (void) { int i; svs.maxclients = 1; i = COM_CheckParm ("-dedicated"); if (i) { cls.state = ca_dedicated; if (i != (com_argc - 1)) { svs.maxclients = Q_atoi (com_argv[i+1]); } else svs.maxclients = 8; } else cls.state = ca_disconnected; i = COM_CheckParm ("-listen"); if (i) { if (cls.state == ca_dedicated) Sys_Error ("Only one of -dedicated or -listen can be specified"); if (i != (com_argc - 1)) svs.maxclients = Q_atoi (com_argv[i+1]); else svs.maxclients = 8; } if (svs.maxclients < 1) svs.maxclients = 8; else if (svs.maxclients > MAX_SCOREBOARD) svs.maxclients = MAX_SCOREBOARD; svs.maxclientslimit = svs.maxclients; if (svs.maxclientslimit < 4) svs.maxclientslimit = 4; svs.clients = (struct client_s *) Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients"); if (svs.maxclients > 1) Cvar_SetQuick (&deathmatch, "1"); else Cvar_SetQuick (&deathmatch, "0"); } void Host_Version_f (void) { Con_Printf ("Quake Version %1.2f\n", VERSION); Con_Printf ("QuakeSpasm Version %1.2f.%d\n", QUAKESPASM_VERSION, QUAKESPASM_VER_PATCH); Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); } /* cvar callback functions : */ void Host_Callback_Notify (cvar_t *var) { if (sv.active) SV_BroadcastPrintf ("\"%s\" changed to \"%s\"\n", var->name, var->string); } /* ======================= Host_InitLocal ====================== */ void Host_InitLocal (void) { Cmd_AddCommand ("version", Host_Version_f); Host_InitCommands (); Cvar_RegisterVariable (&host_framerate); Cvar_RegisterVariable (&host_speeds); Cvar_RegisterVariable (&host_maxfps); //johnfitz Cvar_RegisterVariable (&host_timescale); //johnfitz Cvar_RegisterVariable (&max_edicts); //johnfitz Cvar_SetCallback (&max_edicts, Max_Edicts_f); Cvar_RegisterVariable (&devstats); //johnfitz Cvar_RegisterVariable (&sys_ticrate); Cvar_RegisterVariable (&sys_throttle); Cvar_RegisterVariable (&serverprofile); Cvar_RegisterVariable (&fraglimit); Cvar_RegisterVariable (&timelimit); Cvar_RegisterVariable (&teamplay); Cvar_SetCallback (&fraglimit, Host_Callback_Notify); Cvar_SetCallback (&timelimit, Host_Callback_Notify); Cvar_SetCallback (&teamplay, Host_Callback_Notify); Cvar_RegisterVariable (&samelevel); Cvar_RegisterVariable (&noexit); Cvar_SetCallback (&noexit, Host_Callback_Notify); Cvar_RegisterVariable (&skill); Cvar_RegisterVariable (&developer); Cvar_RegisterVariable (&coop); Cvar_RegisterVariable (&deathmatch); Cvar_RegisterVariable (&pausable); Cvar_RegisterVariable (&temp1); Host_FindMaxClients (); } /* =============== Host_WriteConfiguration Writes key bindings and archived cvars to config.cfg =============== */ void Host_WriteConfiguration (void) { FILE *f; // dedicated servers initialize the host but don't parse and set the // config.cfg cvars if (host_initialized & !isDedicated) { f = fopen (va("%s/config.cfg", com_gamedir), "w"); if (!f) { Con_Printf ("Couldn't write config.cfg.\n"); return; } VID_SyncCvars (); //johnfitz -- write actual current mode to config file, in case cvars were messed with Key_WriteBindings (f); Cvar_WriteVariables (f); //johnfitz -- extra commands to preserve state fprintf (f, "vid_restart\n"); if (in_mlook.state & 1) fprintf (f, "+mlook\n"); //johnfitz fclose (f); //johnfitz -- also save fitzquake.rc #if 0 f = fopen (va("%s/fitzquake.rc", GAMENAME), "w"); //always save in id1 if (!f) { Con_Printf ("Couldn't write fitzquake.rc.\n"); return; } Cvar_WriteVariables (f); fprintf (f, "vid_restart\n"); if (in_mlook.state & 1) fprintf (f, "+mlook\n"); fclose (f); #endif //johnfitz } } /* ================= SV_ClientPrintf Sends text across to be displayed FIXME: make this just a stuffed echo? ================= */ void SV_ClientPrintf (const char *fmt, ...) { va_list argptr; char string[1024]; va_start (argptr,fmt); q_vsnprintf (string, sizeof(string), fmt,argptr); va_end (argptr); MSG_WriteByte (&host_client->message, svc_print); MSG_WriteString (&host_client->message, string); } /* ================= SV_BroadcastPrintf Sends text to all active clients ================= */ void SV_BroadcastPrintf (const char *fmt, ...) { va_list argptr; char string[1024]; int i; va_start (argptr,fmt); q_vsnprintf (string, sizeof(string), fmt, argptr); va_end (argptr); for (i = 0; i < svs.maxclients; i++) { if (svs.clients[i].active && svs.clients[i].spawned) { MSG_WriteByte (&svs.clients[i].message, svc_print); MSG_WriteString (&svs.clients[i].message, string); } } } /* ================= Host_ClientCommands Send text over to the client to be executed ================= */ void Host_ClientCommands (const char *fmt, ...) { va_list argptr; char string[1024]; va_start (argptr,fmt); q_vsnprintf (string, sizeof(string), fmt, argptr); va_end (argptr); MSG_WriteByte (&host_client->message, svc_stufftext); MSG_WriteString (&host_client->message, string); } /* ===================== SV_DropClient Called when the player is getting totally kicked off the host if (crash = true), don't bother sending signofs ===================== */ void SV_DropClient (qboolean crash) { int saveSelf; int i; client_t *client; if (!crash) { // send any final messages (don't check for errors) if (NET_CanSendMessage (host_client->netconnection)) { MSG_WriteByte (&host_client->message, svc_disconnect); NET_SendMessage (host_client->netconnection, &host_client->message); } if (host_client->edict && host_client->spawned) { // call the prog function for removing a client // this will set the body to a dead frame, among other things saveSelf = pr_global_struct->self; pr_global_struct->self = EDICT_TO_PROG(host_client->edict); PR_ExecuteProgram (pr_global_struct->ClientDisconnect); pr_global_struct->self = saveSelf; } Sys_Printf ("Client %s removed\n",host_client->name); } // break the net connection NET_Close (host_client->netconnection); host_client->netconnection = NULL; // free the client (the body stays around) host_client->active = false; host_client->name[0] = 0; host_client->old_frags = -999999; net_activeconnections--; // send notification to all clients for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) { if (!client->active) continue; MSG_WriteByte (&client->message, svc_updatename); MSG_WriteByte (&client->message, host_client - svs.clients); MSG_WriteString (&client->message, ""); MSG_WriteByte (&client->message, svc_updatefrags); MSG_WriteByte (&client->message, host_client - svs.clients); MSG_WriteShort (&client->message, 0); MSG_WriteByte (&client->message, svc_updatecolors); MSG_WriteByte (&client->message, host_client - svs.clients); MSG_WriteByte (&client->message, 0); } } /* ================== Host_ShutdownServer This only happens at the end of a game, not between levels ================== */ void Host_ShutdownServer(qboolean crash) { int i; int count; sizebuf_t buf; byte message[4]; double start; if (!sv.active) return; sv.active = false; // stop all client sounds immediately if (cls.state == ca_connected) CL_Disconnect (); // flush any pending messages - like the score!!! start = Sys_DoubleTime(); do { count = 0; for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) { if (host_client->active && host_client->message.cursize) { if (NET_CanSendMessage (host_client->netconnection)) { NET_SendMessage(host_client->netconnection, &host_client->message); SZ_Clear (&host_client->message); } else { NET_GetMessage(host_client->netconnection); count++; } } } if ((Sys_DoubleTime() - start) > 3.0) break; } while (count); // make sure all the clients know we're disconnecting buf.data = message; buf.maxsize = 4; buf.cursize = 0; MSG_WriteByte(&buf, svc_disconnect); count = NET_SendToAll(&buf, 5.0); if (count) Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count); for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) if (host_client->active) SV_DropClient(crash); // // clear structures // // memset (&sv, 0, sizeof(sv)); // ServerSpawn already do this by Host_ClearMemory memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t)); } /* ================ Host_ClearMemory This clears all the memory used by both the client and server, but does not reinitialize anything. ================ */ void Host_ClearMemory (void) { Con_DPrintf ("Clearing memory\n"); D_FlushCaches (); Mod_ClearAll (); /* host_hunklevel MUST be set at this point */ Hunk_FreeToLowMark (host_hunklevel); cls.signon = 0; memset (&sv, 0, sizeof(sv)); memset (&cl, 0, sizeof(cl)); } //============================================================================== // // Host Frame // //============================================================================== /* =================== Host_FilterTime Returns false if the time is too short to run a frame =================== */ qboolean Host_FilterTime (float time) { float maxfps; //johnfitz realtime += time; //johnfitz -- max fps cvar maxfps = CLAMP (10.0, host_maxfps.value, 1000.0); if (!cls.timedemo && realtime - oldrealtime < 1.0/maxfps) return false; // framerate is too high //johnfitz host_frametime = realtime - oldrealtime; oldrealtime = realtime; //johnfitz -- host_timescale is more intuitive than host_framerate if (host_timescale.value > 0) host_frametime *= host_timescale.value; //johnfitz else if (host_framerate.value > 0) host_frametime = host_framerate.value; else // don't allow really long or short frames host_frametime = CLAMP (0.001, host_frametime, 0.1); //johnfitz -- use CLAMP return true; } /* =================== Host_GetConsoleCommands Add them exactly as if they had been typed at the console =================== */ void Host_GetConsoleCommands (void) { const char *cmd; if (!isDedicated) return; // no stdin necessary in graphical mode while (1) { cmd = Sys_ConsoleInput (); if (!cmd) break; Cbuf_AddText (cmd); } } /* ================== Host_ServerFrame ================== */ void Host_ServerFrame (void) { int i, active; //johnfitz edict_t *ent; //johnfitz // run the world state pr_global_struct->frametime = host_frametime; // set the time and clear the general datagram SV_ClearDatagram (); // check for new clients SV_CheckForNewClients (); // read client messages SV_RunClients (); // move things around and think // always pause in single player if in console or menus if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) SV_Physics (); //johnfitz -- devstats if (cls.signon == SIGNONS) { for (i=0, active=0; i<sv.num_edicts; i++) { ent = EDICT_NUM(i); if (!ent->free) active++; } if (active > 600 && dev_peakstats.edicts <= 600) Con_DWarning ("%i edicts exceeds standard limit of 600.\n", active); dev_stats.edicts = active; dev_peakstats.edicts = q_max(active, dev_peakstats.edicts); } //johnfitz // send all messages to the clients SV_SendClientMessages (); } /* ================== Host_Frame Runs all active servers ================== */ void _Host_Frame (float time) { static double time1 = 0; static double time2 = 0; static double time3 = 0; int pass1, pass2, pass3; if (setjmp (host_abortserver) ) return; // something bad happened, or the server disconnected // keep the random time dependent rand (); // decide the simulation time if (!Host_FilterTime (time)) return; // don't run too fast, or packets will flood out // get new key events Key_UpdateForDest (); IN_UpdateInputMode (); Sys_SendKeyEvents (); // allow mice or other external controllers to add commands IN_Commands (); // process console commands Cbuf_Execute (); NET_Poll(); // if running the server locally, make intentions now if (sv.active) CL_SendCmd (); //------------------- // // server operations // //------------------- // check for commands typed to the host Host_GetConsoleCommands (); if (sv.active) Host_ServerFrame (); //------------------- // // client operations // //------------------- // if running the server remotely, send intentions now after // the incoming messages have been read if (!sv.active) CL_SendCmd (); // fetch results from server if (cls.state == ca_connected) CL_ReadFromServer (); // update video if (host_speeds.value) time1 = Sys_DoubleTime (); SCR_UpdateScreen (); CL_RunParticles (); //johnfitz -- seperated from rendering if (host_speeds.value) time2 = Sys_DoubleTime (); // update audio BGM_Update(); // adds music raw samples and/or advances midi driver if (cls.signon == SIGNONS) { S_Update (r_origin, vpn, vright, vup); CL_DecayLights (); } else S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin); CDAudio_Update(); if (host_speeds.value) { pass1 = (time1 - time3)*1000; time3 = Sys_DoubleTime (); pass2 = (time2 - time1)*1000; pass3 = (time3 - time2)*1000; Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n", pass1+pass2+pass3, pass1, pass2, pass3); } host_framecount++; } void Host_Frame (float time) { double time1, time2; static double timetotal; static int timecount; int i, c, m; if (!serverprofile.value) { _Host_Frame (time); return; } time1 = Sys_DoubleTime (); _Host_Frame (time); time2 = Sys_DoubleTime (); timetotal += time2 - time1; timecount++; if (timecount < 1000) return; m = timetotal*1000/timecount; timecount = 0; timetotal = 0; c = 0; for (i = 0; i < svs.maxclients; i++) { if (svs.clients[i].active) c++; } Con_Printf ("serverprofile: %2i clients %2i msec\n", c, m); } /* ==================== Host_Init ==================== */ void Host_Init (void) { if (standard_quake) minimum_memory = MINIMUM_MEMORY; else minimum_memory = MINIMUM_MEMORY_LEVELPAK; if (COM_CheckParm ("-minmemory")) host_parms->memsize = minimum_memory; if (host_parms->memsize < minimum_memory) Sys_Error ("Only %4.1f megs of memory available, can't execute game", host_parms->memsize / (float)0x100000); com_argc = host_parms->argc; com_argv = host_parms->argv; Memory_Init (host_parms->membase, host_parms->memsize); Cbuf_Init (); Cmd_Init (); LOG_Init (host_parms); Cvar_Init (); //johnfitz COM_Init (); COM_InitFilesystem (); Host_InitLocal (); W_LoadWadFile (); //johnfitz -- filename is now hard-coded for honesty if (cls.state != ca_dedicated) { Key_Init (); Con_Init (); } PR_Init (); Mod_Init (); NET_Init (); SV_Init (); Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); Con_Printf ("%4.1f megabyte heap\n", host_parms->memsize/ (1024*1024.0)); if (cls.state != ca_dedicated) { host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp", NULL); if (!host_colormap) Sys_Error ("Couldn't load gfx/colormap.lmp"); V_Init (); Chase_Init (); M_Init (); ExtraMaps_Init (); //johnfitz Modlist_Init (); //johnfitz DemoList_Init (); //ericw VID_Init (); IN_Init (); TexMgr_Init (); //johnfitz Draw_Init (); SCR_Init (); R_Init (); S_Init (); CDAudio_Init (); BGM_Init(); Sbar_Init (); CL_Init (); } Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); host_hunklevel = Hunk_LowMark (); host_initialized = true; Con_Printf ("\n========= Quake Initialized =========\n\n"); if (cls.state != ca_dedicated) { Cbuf_InsertText ("exec quake.rc\n"); // johnfitz -- in case the vid mode was locked during vid_init, we can unlock it now. // note: two leading newlines because the command buffer swallows one of them. Cbuf_AddText ("\n\nvid_unlock\n"); } if (cls.state == ca_dedicated) { Cbuf_AddText ("exec autoexec.cfg\n"); Cbuf_AddText ("stuffcmds"); Cbuf_Execute (); if (!sv.active) Cbuf_AddText ("map start\n"); } } /* =============== Host_Shutdown FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better to run quit through here before the final handoff to the sys code. =============== */ void Host_Shutdown(void) { static qboolean isdown = false; if (isdown) { printf ("recursive shutdown\n"); return; } isdown = true; // keep Con_Printf from trying to update the screen scr_disabled_for_loading = true; Host_WriteConfiguration (); NET_Shutdown (); if (cls.state != ca_dedicated) { if (con_initialized) History_Shutdown (); BGM_Shutdown(); CDAudio_Shutdown (); S_Shutdown (); IN_Shutdown (); VID_Shutdown(); } LOG_Close (); } ���������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_umx.h�������������������������������������������������������������������0000644�0000000�0000000�00000000302�12220541170�015332� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Unreal UMX format support */ #if !defined(_SND_UMX_H_) #define _SND_UMX_H_ #if defined(USE_CODEC_UMX) extern snd_codec_t umx_codec; #endif /* USE_CODEC_UMX */ #endif /* ! _SND_UMX_H_ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/render.h��������������������������������������������������������������������0000644�0000000�0000000�00000014120�12407762022�015147� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_RENDER_H #define _QUAKE_RENDER_H // refresh.h -- public interface to refresh functions #define MAXCLIPPLANES 11 #define TOP_RANGE 16 // soldier uniform colors #define BOTTOM_RANGE 96 //============================================================================= typedef struct efrag_s { struct mleaf_s *leaf; struct efrag_s *leafnext; struct entity_s *entity; struct efrag_s *entnext; } efrag_t; //johnfitz -- for lerping #define LERP_MOVESTEP (1<<0) //this is a MOVETYPE_STEP entity, enable movement lerp #define LERP_RESETANIM (1<<1) //disable anim lerping until next anim frame #define LERP_RESETANIM2 (1<<2) //set this and previous flag to disable anim lerping for two anim frames #define LERP_RESETMOVE (1<<3) //disable movement lerping until next origin/angles change #define LERP_FINISH (1<<4) //use lerpfinish time from server update instead of assuming interval of 0.1 //johnfitz typedef struct entity_s { qboolean forcelink; // model changed int update_type; entity_state_t baseline; // to fill in defaults in updates double msgtime; // time of last update vec3_t msg_origins[2]; // last two updates (0 is newest) vec3_t origin; vec3_t msg_angles[2]; // last two updates (0 is newest) vec3_t angles; struct qmodel_s *model; // NULL = no model struct efrag_s *efrag; // linked list of efrags int frame; float syncbase; // for client-side animations byte *colormap; int effects; // light, particles, etc int skinnum; // for Alias models int visframe; // last frame this entity was // found in an active leaf int dlightframe; // dynamic lighting int dlightbits; // FIXME: could turn these into a union int trivial_accept; struct mnode_s *topnode; // for bmodels, first world node // that splits bmodel, or NULL if // not split byte alpha; //johnfitz -- alpha byte lerpflags; //johnfitz -- lerping float lerpstart; //johnfitz -- animation lerping float lerptime; //johnfitz -- animation lerping float lerpfinish; //johnfitz -- lerping -- server sent us a more accurate interval, use it instead of 0.1 short previouspose; //johnfitz -- animation lerping short currentpose; //johnfitz -- animation lerping // short futurepose; //johnfitz -- animation lerping float movelerpstart; //johnfitz -- transform lerping vec3_t previousorigin; //johnfitz -- transform lerping vec3_t currentorigin; //johnfitz -- transform lerping vec3_t previousangles; //johnfitz -- transform lerping vec3_t currentangles; //johnfitz -- transform lerping } entity_t; // !!! if this is changed, it must be changed in asm_draw.h too !!! typedef struct { vrect_t vrect; // subwindow in video for refresh // FIXME: not need vrect next field here? vrect_t aliasvrect; // scaled Alias version int vrectright, vrectbottom; // right & bottom screen coords int aliasvrectright, aliasvrectbottom; // scaled Alias versions float vrectrightedge; // rightmost right edge we care about, // for use in edge list float fvrectx, fvrecty; // for floating-point compares float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20 int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20 float fvrectright_adj, fvrectbottom_adj; // right and bottom edges, for clamping float fvrectright; // rightmost edge, for Alias clamping float fvrectbottom; // bottommost edge, for Alias clamping float horizontalFieldOfView; // at Z = 1.0, this many X is visible // 2.0 = 90 degrees float xOrigin; // should probably allways be 0.5 float yOrigin; // between be around 0.3 to 0.5 vec3_t vieworg; vec3_t viewangles; float fov_x, fov_y; int ambientlight; } refdef_t; // // refresh // extern int reinit_surfcache; extern refdef_t r_refdef; extern vec3_t r_origin, vpn, vright, vup; void R_Init (void); void R_InitTextures (void); void R_InitEfrags (void); void R_RenderView (void); // must set r_refdef first void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect); // called whenever r_refdef or vid change //void R_InitSky (struct texture_s *mt); // called at level load void R_CheckEfrags (void); //johnfitz void R_AddEfrags (entity_t *ent); void R_RemoveEfrags (entity_t *ent); void R_NewMap (void); void R_ParseParticleEffect (void); void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count); void R_RocketTrail (vec3_t start, vec3_t end, int type); void R_EntityParticles (entity_t *ent); void R_BlobExplosion (vec3_t org); void R_ParticleExplosion (vec3_t org); void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength); void R_LavaSplash (vec3_t org); void R_TeleportSplash (vec3_t org); void R_PushDlights (void); // // surface cache related // extern int reinit_surfcache; // if 1, surface cache is currently empty and extern qboolean r_cache_thrash; // set if thrashing the surface cache int D_SurfaceCacheForRes (int width, int height); void D_FlushCaches (void); void D_DeleteSurfaceCache (void); void D_InitCaches (void *buffer, int size); void R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj); #endif /* _QUAKE_RENDER_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cdaudio.h�������������������������������������������������������������������0000644�0000000�0000000�00000002116�12407762022�015302� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __CDAUDIO_H #define __CDAUDIO_H int CDAudio_Init (void); int CDAudio_Play (byte track, qboolean looping); /* returns 0 for success, -1 for failure. */ void CDAudio_Stop (void); void CDAudio_Pause (void); void CDAudio_Resume (void); void CDAudio_Shutdown (void); void CDAudio_Update (void); #endif /* __CDAUDIO_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/cfgfile.h�������������������������������������������������������������������0000644�0000000�0000000�00000003024�12407762022�015270� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * cfgfile.h -- misc reads from the config file * * Copyright (C) 2008-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #ifndef __CFGFILE_H #define __CFGFILE_H int CFG_OpenConfig (const char *cfg_name); // opens the given config file. only one open config file is // kept: previosly opened one, if any, will be closed. void CFG_CloseConfig (void); // closes the currently open config file. void CFG_ReadCvars (const char **vars, int num_vars); // reads the values of cvars in the given list from the opened // config file. void CFG_ReadCvarOverrides (const char **vars, int num_vars); // convenience function, reading the "+" command line override // values of cvars in the given list. doesn't do anything with // the config file. call this after CFG_ReadCvars() and before // locking your cvars. #endif /* __CFGFILE_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sv_main.c�������������������������������������������������������������������0000644�0000000�0000000�00000106165�12530477523�015340� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_main.c -- server main program #include "quakedef.h" server_t sv; server_static_t svs; static char localmodels[MAX_MODELS][8]; // inline model names for precache int sv_protocol = PROTOCOL_FITZQUAKE; //johnfitz extern qboolean pr_alpha_supported; //johnfitz //============================================================================ /* =============== SV_Protocol_f =============== */ void SV_Protocol_f (void) { int i; switch (Cmd_Argc()) { case 1: Con_Printf ("\"sv_protocol\" is \"%i\"\n", sv_protocol); break; case 2: i = atoi(Cmd_Argv(1)); if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) Con_Printf ("sv_protocol must be %i or %i\n", PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); else { sv_protocol = i; if (sv.active) Con_Printf ("changes will not take effect until the next level load.\n"); } break; default: Con_SafePrintf ("usage: sv_protocol <protocol>\n"); break; } } /* =============== SV_Init =============== */ void SV_Init (void) { int i; extern cvar_t sv_maxvelocity; extern cvar_t sv_gravity; extern cvar_t sv_nostep; extern cvar_t sv_freezenonclients; extern cvar_t sv_friction; extern cvar_t sv_edgefriction; extern cvar_t sv_stopspeed; extern cvar_t sv_maxspeed; extern cvar_t sv_accelerate; extern cvar_t sv_idealpitchscale; extern cvar_t sv_aim; extern cvar_t sv_altnoclip; //johnfitz Cvar_RegisterVariable (&sv_maxvelocity); Cvar_RegisterVariable (&sv_gravity); Cvar_RegisterVariable (&sv_friction); Cvar_SetCallback (&sv_gravity, Host_Callback_Notify); Cvar_SetCallback (&sv_friction, Host_Callback_Notify); Cvar_RegisterVariable (&sv_edgefriction); Cvar_RegisterVariable (&sv_stopspeed); Cvar_RegisterVariable (&sv_maxspeed); Cvar_SetCallback (&sv_maxspeed, Host_Callback_Notify); Cvar_RegisterVariable (&sv_accelerate); Cvar_RegisterVariable (&sv_idealpitchscale); Cvar_RegisterVariable (&sv_aim); Cvar_RegisterVariable (&sv_nostep); Cvar_RegisterVariable (&sv_freezenonclients); Cvar_RegisterVariable (&sv_altnoclip); //johnfitz Cmd_AddCommand ("sv_protocol", &SV_Protocol_f); //johnfitz for (i=0 ; i<MAX_MODELS ; i++) sprintf (localmodels[i], "*%i", i); } /* ============================================================================= EVENT MESSAGES ============================================================================= */ /* ================== SV_StartParticle Make sure the event gets sent to all clients ================== */ void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count) { int i, v; if (sv.datagram.cursize > MAX_DATAGRAM-16) return; MSG_WriteByte (&sv.datagram, svc_particle); MSG_WriteCoord (&sv.datagram, org[0]); MSG_WriteCoord (&sv.datagram, org[1]); MSG_WriteCoord (&sv.datagram, org[2]); for (i=0 ; i<3 ; i++) { v = dir[i]*16; if (v > 127) v = 127; else if (v < -128) v = -128; MSG_WriteChar (&sv.datagram, v); } MSG_WriteByte (&sv.datagram, count); MSG_WriteByte (&sv.datagram, color); } /* ================== SV_StartSound Each entity can have eight independant sound sources, like voice, weapon, feet, etc. Channel 0 is an auto-allocate channel, the others override anything allready running on that entity/channel pair. An attenuation of 0 will play full volume everywhere in the level. Larger attenuations will drop off. (max 4 attenuation) ================== */ void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume, float attenuation) { int sound_num, ent; int i, field_mask; if (volume < 0 || volume > 255) Host_Error ("SV_StartSound: volume = %i", volume); if (attenuation < 0 || attenuation > 4) Host_Error ("SV_StartSound: attenuation = %f", attenuation); if (channel < 0 || channel > 7) Host_Error ("SV_StartSound: channel = %i", channel); if (sv.datagram.cursize > MAX_DATAGRAM-16) return; // find precache number for sound for (sound_num = 1; sound_num < MAX_SOUNDS && sv.sound_precache[sound_num]; sound_num++) { if (!strcmp(sample, sv.sound_precache[sound_num])) break; } if (sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num]) { Con_Printf ("SV_StartSound: %s not precacheed\n", sample); return; } ent = NUM_FOR_EDICT(entity); field_mask = 0; if (volume != DEFAULT_SOUND_PACKET_VOLUME) field_mask |= SND_VOLUME; if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) field_mask |= SND_ATTENUATION; //johnfitz -- PROTOCOL_FITZQUAKE if (ent >= 8192) { if (sv.protocol == PROTOCOL_NETQUAKE) return; //don't send any info protocol can't support else field_mask |= SND_LARGEENTITY; } if (sound_num >= 256 || channel >= 8) { if (sv.protocol == PROTOCOL_NETQUAKE) return; //don't send any info protocol can't support else field_mask |= SND_LARGESOUND; } //johnfitz // directed messages go only to the entity the are targeted on MSG_WriteByte (&sv.datagram, svc_sound); MSG_WriteByte (&sv.datagram, field_mask); if (field_mask & SND_VOLUME) MSG_WriteByte (&sv.datagram, volume); if (field_mask & SND_ATTENUATION) MSG_WriteByte (&sv.datagram, attenuation*64); //johnfitz -- PROTOCOL_FITZQUAKE if (field_mask & SND_LARGEENTITY) { MSG_WriteShort (&sv.datagram, ent); MSG_WriteByte (&sv.datagram, channel); } else MSG_WriteShort (&sv.datagram, (ent<<3) | channel); if (field_mask & SND_LARGESOUND) MSG_WriteShort (&sv.datagram, sound_num); else MSG_WriteByte (&sv.datagram, sound_num); //johnfitz for (i = 0; i < 3; i++) MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i])); } /* ============================================================================== CLIENT SPAWNING ============================================================================== */ /* ================ SV_SendServerinfo Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each server load. ================ */ void SV_SendServerinfo (client_t *client) { const char **s; char message[2048]; int i; //johnfitz MSG_WriteByte (&client->message, svc_print); sprintf (message, "%c\nFITZQUAKE %1.2f SERVER (%i CRC)\n", 2, FITZQUAKE_VERSION, pr_crc); //johnfitz -- include fitzquake version MSG_WriteString (&client->message,message); MSG_WriteByte (&client->message, svc_serverinfo); MSG_WriteLong (&client->message, sv.protocol); //johnfitz -- sv.protocol instead of PROTOCOL_VERSION MSG_WriteByte (&client->message, svs.maxclients); if (!coop.value && deathmatch.value) MSG_WriteByte (&client->message, GAME_DEATHMATCH); else MSG_WriteByte (&client->message, GAME_COOP); MSG_WriteString (&client->message, PR_GetString(sv.edicts->v.message)); //johnfitz -- only send the first 256 model and sound precaches if protocol is 15 for (i=0,s = sv.model_precache+1 ; *s; s++,i++) if (sv.protocol != PROTOCOL_NETQUAKE || i < 256) MSG_WriteString (&client->message, *s); MSG_WriteByte (&client->message, 0); for (i=0,s = sv.sound_precache+1 ; *s ; s++,i++) if (sv.protocol != PROTOCOL_NETQUAKE || i < 256) MSG_WriteString (&client->message, *s); MSG_WriteByte (&client->message, 0); //johnfitz // send music MSG_WriteByte (&client->message, svc_cdtrack); MSG_WriteByte (&client->message, sv.edicts->v.sounds); MSG_WriteByte (&client->message, sv.edicts->v.sounds); // set view MSG_WriteByte (&client->message, svc_setview); MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict)); MSG_WriteByte (&client->message, svc_signonnum); MSG_WriteByte (&client->message, 1); client->sendsignon = true; client->spawned = false; // need prespawn, spawn, etc } /* ================ SV_ConnectClient Initializes a client_t for a new net connection. This will only be called once for a player each game, not once for each level change. ================ */ void SV_ConnectClient (int clientnum) { edict_t *ent; client_t *client; int edictnum; struct qsocket_s *netconnection; int i; float spawn_parms[NUM_SPAWN_PARMS]; client = svs.clients + clientnum; Con_DPrintf ("Client %s connected\n", NET_QSocketGetAddressString(client->netconnection)); edictnum = clientnum+1; ent = EDICT_NUM(edictnum); // set up the client_t netconnection = client->netconnection; if (sv.loadgame) memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms)); memset (client, 0, sizeof(*client)); client->netconnection = netconnection; strcpy (client->name, "unconnected"); client->active = true; client->spawned = false; client->edict = ent; client->message.data = client->msgbuf; client->message.maxsize = sizeof(client->msgbuf); client->message.allowoverflow = true; // we can catch it if (sv.loadgame) memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms)); else { // call the progs to get default spawn parms for the new client PR_ExecuteProgram (pr_global_struct->SetNewParms); for (i=0 ; i<NUM_SPAWN_PARMS ; i++) client->spawn_parms[i] = (&pr_global_struct->parm1)[i]; } SV_SendServerinfo (client); } /* =================== SV_CheckForNewClients =================== */ void SV_CheckForNewClients (void) { struct qsocket_s *ret; int i; // // check for new connections // while (1) { ret = NET_CheckNewConnections (); if (!ret) break; // // init a new client structure // for (i=0 ; i<svs.maxclients ; i++) if (!svs.clients[i].active) break; if (i == svs.maxclients) Sys_Error ("Host_CheckForNewClients: no free clients"); svs.clients[i].netconnection = ret; SV_ConnectClient (i); net_activeconnections++; } } /* =============================================================================== FRAME UPDATES =============================================================================== */ /* ================== SV_ClearDatagram ================== */ void SV_ClearDatagram (void) { SZ_Clear (&sv.datagram); } /* ============================================================================= The PVS must include a small area around the client to allow head bobbing or other small motion on the client side. Otherwise, a bob might cause an entity that should be visible to not show up, especially when the bob crosses a waterline. ============================================================================= */ int fatbytes; byte fatpvs[MAX_MAP_LEAFS/8]; void SV_AddToFatPVS (vec3_t org, mnode_t *node, qmodel_t *worldmodel) //johnfitz -- added worldmodel as a parameter { int i; byte *pvs; mplane_t *plane; float d; while (1) { // if this is a leaf, accumulate the pvs bits if (node->contents < 0) { if (node->contents != CONTENTS_SOLID) { pvs = Mod_LeafPVS ( (mleaf_t *)node, worldmodel); //johnfitz -- worldmodel as a parameter for (i=0 ; i<fatbytes ; i++) fatpvs[i] |= pvs[i]; } return; } plane = node->plane; d = DotProduct (org, plane->normal) - plane->dist; if (d > 8) node = node->children[0]; else if (d < -8) node = node->children[1]; else { // go down both SV_AddToFatPVS (org, node->children[0], worldmodel); //johnfitz -- worldmodel as a parameter node = node->children[1]; } } } /* ============= SV_FatPVS Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the given point. ============= */ byte *SV_FatPVS (vec3_t org, qmodel_t *worldmodel) //johnfitz -- added worldmodel as a parameter { fatbytes = (worldmodel->numleafs+31)>>3; Q_memset (fatpvs, 0, fatbytes); SV_AddToFatPVS (org, worldmodel->nodes, worldmodel); //johnfitz -- worldmodel as a parameter return fatpvs; } /* ============= SV_VisibleToClient -- johnfitz PVS test encapsulated in a nice function ============= */ qboolean SV_VisibleToClient (edict_t *client, edict_t *test, qmodel_t *worldmodel) { byte *pvs; vec3_t org; int i; VectorAdd (client->v.origin, client->v.view_ofs, org); pvs = SV_FatPVS (org, worldmodel); for (i=0 ; i < test->num_leafs ; i++) if (pvs[test->leafnums[i] >> 3] & (1 << (test->leafnums[i]&7) )) return true; return false; } //============================================================================= /* ============= SV_WriteEntitiesToClient ============= */ void SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg) { int e, i; int bits; byte *pvs; vec3_t org; float miss; edict_t *ent; // find the client's PVS VectorAdd (clent->v.origin, clent->v.view_ofs, org); pvs = SV_FatPVS (org, sv.worldmodel); // send over all entities (excpet the client) that touch the pvs ent = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent)) { if (ent != clent) // clent is ALLWAYS sent { // ignore ents without visible models if (!ent->v.modelindex || !PR_GetString(ent->v.model)[0]) continue; //johnfitz -- don't send model>255 entities if protocol is 15 if (sv.protocol == PROTOCOL_NETQUAKE && (int)ent->v.modelindex & 0xFF00) continue; // ignore if not touching a PV leaf for (i=0 ; i < ent->num_leafs ; i++) if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) break; // ericw -- added ent->num_leafs < MAX_ENT_LEAFS condition. // // if ent->num_leafs == MAX_ENT_LEAFS, the ent is visible from too many leafs // for us to say whether it's in the PVS, so don't try to vis cull it. // this commonly happens with rotators, because they often have huge bboxes // spanning the entire map, or really tall lifts, etc. if (i == ent->num_leafs && ent->num_leafs < MAX_ENT_LEAFS) continue; // not visible } //johnfitz -- max size for protocol 15 is 18 bytes, not 16 as originally //assumed here. And, for protocol 85 the max size is actually 24 bytes. if (msg->cursize + 24 > msg->maxsize) { //johnfitz -- less spammy overflow message if (!dev_overflows.packetsize || dev_overflows.packetsize + CONSOLE_RESPAM_TIME < realtime ) { Con_Printf ("Packet overflow!\n"); dev_overflows.packetsize = realtime; } goto stats; //johnfitz } // send an update bits = 0; for (i=0 ; i<3 ; i++) { miss = ent->v.origin[i] - ent->baseline.origin[i]; if ( miss < -0.1 || miss > 0.1 ) bits |= U_ORIGIN1<<i; } if ( ent->v.angles[0] != ent->baseline.angles[0] ) bits |= U_ANGLE1; if ( ent->v.angles[1] != ent->baseline.angles[1] ) bits |= U_ANGLE2; if ( ent->v.angles[2] != ent->baseline.angles[2] ) bits |= U_ANGLE3; if (ent->v.movetype == MOVETYPE_STEP) bits |= U_STEP; // don't mess up the step animation if (ent->baseline.colormap != ent->v.colormap) bits |= U_COLORMAP; if (ent->baseline.skin != ent->v.skin) bits |= U_SKIN; if (ent->baseline.frame != ent->v.frame) bits |= U_FRAME; if (ent->baseline.effects != ent->v.effects) bits |= U_EFFECTS; if (ent->baseline.modelindex != ent->v.modelindex) bits |= U_MODEL; //johnfitz -- alpha if (pr_alpha_supported) { // TODO: find a cleaner place to put this code eval_t *val; val = GetEdictFieldValue(ent, "alpha"); if (val) ent->alpha = ENTALPHA_ENCODE(val->_float); } //don't send invisible entities unless they have effects if (ent->alpha == ENTALPHA_ZERO && !ent->v.effects) continue; //johnfitz //johnfitz -- PROTOCOL_FITZQUAKE if (sv.protocol != PROTOCOL_NETQUAKE) { if (ent->baseline.alpha != ent->alpha) bits |= U_ALPHA; if (bits & U_FRAME && (int)ent->v.frame & 0xFF00) bits |= U_FRAME2; if (bits & U_MODEL && (int)ent->v.modelindex & 0xFF00) bits |= U_MODEL2; if (ent->sendinterval) bits |= U_LERPFINISH; if (bits >= 65536) bits |= U_EXTEND1; if (bits >= 16777216) bits |= U_EXTEND2; } //johnfitz if (e >= 256) bits |= U_LONGENTITY; if (bits >= 256) bits |= U_MOREBITS; // // write the message // MSG_WriteByte (msg, bits | U_SIGNAL); if (bits & U_MOREBITS) MSG_WriteByte (msg, bits>>8); //johnfitz -- PROTOCOL_FITZQUAKE if (bits & U_EXTEND1) MSG_WriteByte(msg, bits>>16); if (bits & U_EXTEND2) MSG_WriteByte(msg, bits>>24); //johnfitz if (bits & U_LONGENTITY) MSG_WriteShort (msg,e); else MSG_WriteByte (msg,e); if (bits & U_MODEL) MSG_WriteByte (msg, ent->v.modelindex); if (bits & U_FRAME) MSG_WriteByte (msg, ent->v.frame); if (bits & U_COLORMAP) MSG_WriteByte (msg, ent->v.colormap); if (bits & U_SKIN) MSG_WriteByte (msg, ent->v.skin); if (bits & U_EFFECTS) MSG_WriteByte (msg, ent->v.effects); if (bits & U_ORIGIN1) MSG_WriteCoord (msg, ent->v.origin[0]); if (bits & U_ANGLE1) MSG_WriteAngle(msg, ent->v.angles[0]); if (bits & U_ORIGIN2) MSG_WriteCoord (msg, ent->v.origin[1]); if (bits & U_ANGLE2) MSG_WriteAngle(msg, ent->v.angles[1]); if (bits & U_ORIGIN3) MSG_WriteCoord (msg, ent->v.origin[2]); if (bits & U_ANGLE3) MSG_WriteAngle(msg, ent->v.angles[2]); //johnfitz -- PROTOCOL_FITZQUAKE if (bits & U_ALPHA) MSG_WriteByte(msg, ent->alpha); if (bits & U_FRAME2) MSG_WriteByte(msg, (int)ent->v.frame >> 8); if (bits & U_MODEL2) MSG_WriteByte(msg, (int)ent->v.modelindex >> 8); if (bits & U_LERPFINISH) MSG_WriteByte(msg, (byte)(Q_rint((ent->v.nextthink-sv.time)*255))); //johnfitz } //johnfitz -- devstats stats: if (msg->cursize > 1024 && dev_peakstats.packetsize <= 1024) Con_DWarning ("%i byte packet exceeds standard limit of 1024.\n", msg->cursize); dev_stats.packetsize = msg->cursize; dev_peakstats.packetsize = q_max(msg->cursize, dev_peakstats.packetsize); //johnfitz } /* ============= SV_CleanupEnts ============= */ void SV_CleanupEnts (void) { int e; edict_t *ent; ent = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent)) { ent->v.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH; } } /* ================== SV_WriteClientdataToMessage ================== */ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) { int bits; int i; edict_t *other; int items; eval_t *val; // // send a damage message // if (ent->v.dmg_take || ent->v.dmg_save) { other = PROG_TO_EDICT(ent->v.dmg_inflictor); MSG_WriteByte (msg, svc_damage); MSG_WriteByte (msg, ent->v.dmg_save); MSG_WriteByte (msg, ent->v.dmg_take); for (i=0 ; i<3 ; i++) MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i])); ent->v.dmg_take = 0; ent->v.dmg_save = 0; } // // send the current viewpos offset from the view entity // SV_SetIdealPitch (); // how much to look up / down ideally // a fixangle might get lost in a dropped packet. Oh well. if ( ent->v.fixangle ) { MSG_WriteByte (msg, svc_setangle); for (i=0 ; i < 3 ; i++) MSG_WriteAngle (msg, ent->v.angles[i] ); ent->v.fixangle = 0; } bits = 0; if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT; if (ent->v.idealpitch) bits |= SU_IDEALPITCH; // stuff the sigil bits into the high bits of items for sbar, or else // mix in items2 val = GetEdictFieldValue(ent, "items2"); if (val) items = (int)ent->v.items | ((int)val->_float << 23); else items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28); bits |= SU_ITEMS; if ( (int)ent->v.flags & FL_ONGROUND) bits |= SU_ONGROUND; if ( ent->v.waterlevel >= 2) bits |= SU_INWATER; for (i=0 ; i<3 ; i++) { if (ent->v.punchangle[i]) bits |= (SU_PUNCH1<<i); if (ent->v.velocity[i]) bits |= (SU_VELOCITY1<<i); } if (ent->v.weaponframe) bits |= SU_WEAPONFRAME; if (ent->v.armorvalue) bits |= SU_ARMOR; // if (ent->v.weapon) bits |= SU_WEAPON; //johnfitz -- PROTOCOL_FITZQUAKE if (sv.protocol != PROTOCOL_NETQUAKE) { if (bits & SU_WEAPON && SV_ModelIndex(PR_GetString(ent->v.weaponmodel)) & 0xFF00) bits |= SU_WEAPON2; if ((int)ent->v.armorvalue & 0xFF00) bits |= SU_ARMOR2; if ((int)ent->v.currentammo & 0xFF00) bits |= SU_AMMO2; if ((int)ent->v.ammo_shells & 0xFF00) bits |= SU_SHELLS2; if ((int)ent->v.ammo_nails & 0xFF00) bits |= SU_NAILS2; if ((int)ent->v.ammo_rockets & 0xFF00) bits |= SU_ROCKETS2; if ((int)ent->v.ammo_cells & 0xFF00) bits |= SU_CELLS2; if (bits & SU_WEAPONFRAME && (int)ent->v.weaponframe & 0xFF00) bits |= SU_WEAPONFRAME2; if (bits & SU_WEAPON && ent->alpha != ENTALPHA_DEFAULT) bits |= SU_WEAPONALPHA; //for now, weaponalpha = client entity alpha if (bits >= 65536) bits |= SU_EXTEND1; if (bits >= 16777216) bits |= SU_EXTEND2; } //johnfitz // send the data MSG_WriteByte (msg, svc_clientdata); MSG_WriteShort (msg, bits); //johnfitz -- PROTOCOL_FITZQUAKE if (bits & SU_EXTEND1) MSG_WriteByte(msg, bits>>16); if (bits & SU_EXTEND2) MSG_WriteByte(msg, bits>>24); //johnfitz if (bits & SU_VIEWHEIGHT) MSG_WriteChar (msg, ent->v.view_ofs[2]); if (bits & SU_IDEALPITCH) MSG_WriteChar (msg, ent->v.idealpitch); for (i=0 ; i<3 ; i++) { if (bits & (SU_PUNCH1<<i)) MSG_WriteChar (msg, ent->v.punchangle[i]); if (bits & (SU_VELOCITY1<<i)) MSG_WriteChar (msg, ent->v.velocity[i]/16); } // [always sent] if (bits & SU_ITEMS) MSG_WriteLong (msg, items); if (bits & SU_WEAPONFRAME) MSG_WriteByte (msg, ent->v.weaponframe); if (bits & SU_ARMOR) MSG_WriteByte (msg, ent->v.armorvalue); if (bits & SU_WEAPON) MSG_WriteByte (msg, SV_ModelIndex(PR_GetString(ent->v.weaponmodel))); MSG_WriteShort (msg, ent->v.health); MSG_WriteByte (msg, ent->v.currentammo); MSG_WriteByte (msg, ent->v.ammo_shells); MSG_WriteByte (msg, ent->v.ammo_nails); MSG_WriteByte (msg, ent->v.ammo_rockets); MSG_WriteByte (msg, ent->v.ammo_cells); if (standard_quake) { MSG_WriteByte (msg, ent->v.weapon); } else { for(i=0;i<32;i++) { if ( ((int)ent->v.weapon) & (1<<i) ) { MSG_WriteByte (msg, i); break; } } } //johnfitz -- PROTOCOL_FITZQUAKE if (bits & SU_WEAPON2) MSG_WriteByte (msg, SV_ModelIndex(PR_GetString(ent->v.weaponmodel)) >> 8); if (bits & SU_ARMOR2) MSG_WriteByte (msg, (int)ent->v.armorvalue >> 8); if (bits & SU_AMMO2) MSG_WriteByte (msg, (int)ent->v.currentammo >> 8); if (bits & SU_SHELLS2) MSG_WriteByte (msg, (int)ent->v.ammo_shells >> 8); if (bits & SU_NAILS2) MSG_WriteByte (msg, (int)ent->v.ammo_nails >> 8); if (bits & SU_ROCKETS2) MSG_WriteByte (msg, (int)ent->v.ammo_rockets >> 8); if (bits & SU_CELLS2) MSG_WriteByte (msg, (int)ent->v.ammo_cells >> 8); if (bits & SU_WEAPONFRAME2) MSG_WriteByte (msg, (int)ent->v.weaponframe >> 8); if (bits & SU_WEAPONALPHA) MSG_WriteByte (msg, ent->alpha); //for now, weaponalpha = client entity alpha //johnfitz } /* ======================= SV_SendClientDatagram ======================= */ qboolean SV_SendClientDatagram (client_t *client) { byte buf[MAX_DATAGRAM]; sizebuf_t msg; msg.data = buf; msg.maxsize = sizeof(buf); msg.cursize = 0; //johnfitz -- if client is nonlocal, use smaller max size so packets aren't fragmented if (Q_strcmp(NET_QSocketGetAddressString(client->netconnection), "LOCAL") != 0) msg.maxsize = DATAGRAM_MTU; //johnfitz MSG_WriteByte (&msg, svc_time); MSG_WriteFloat (&msg, sv.time); // add the client specific data to the datagram SV_WriteClientdataToMessage (client->edict, &msg); SV_WriteEntitiesToClient (client->edict, &msg); // copy the server datagram if there is space if (msg.cursize + sv.datagram.cursize < msg.maxsize) SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize); // send the datagram if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) { SV_DropClient (true);// if the message couldn't send, kick off return false; } return true; } /* ======================= SV_UpdateToReliableMessages ======================= */ void SV_UpdateToReliableMessages (void) { int i, j; client_t *client; // check for changes to be sent over the reliable streams for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) { if (host_client->old_frags != host_client->edict->v.frags) { for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++) { if (!client->active) continue; MSG_WriteByte (&client->message, svc_updatefrags); MSG_WriteByte (&client->message, i); MSG_WriteShort (&client->message, host_client->edict->v.frags); } host_client->old_frags = host_client->edict->v.frags; } } for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++) { if (!client->active) continue; SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); } SZ_Clear (&sv.reliable_datagram); } /* ======================= SV_SendNop Send a nop message without trashing or sending the accumulated client message buffer ======================= */ void SV_SendNop (client_t *client) { sizebuf_t msg; byte buf[4]; msg.data = buf; msg.maxsize = sizeof(buf); msg.cursize = 0; MSG_WriteChar (&msg, svc_nop); if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) SV_DropClient (true); // if the message couldn't send, kick off client->last_message = realtime; } /* ======================= SV_SendClientMessages ======================= */ void SV_SendClientMessages (void) { int i; // update frags, names, etc SV_UpdateToReliableMessages (); // build individual updates for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) { if (!host_client->active) continue; if (host_client->spawned) { if (!SV_SendClientDatagram (host_client)) continue; } else { // the player isn't totally in the game yet // send small keepalive messages if too much time has passed // send a full message when the next signon stage has been requested // some other message data (name changes, etc) may accumulate // between signon stages if (!host_client->sendsignon) { if (realtime - host_client->last_message > 5) SV_SendNop (host_client); continue; // don't send out non-signon messages } } // check for an overflowed message. Should only happen // on a very fucked up connection that backs up a lot, then // changes level if (host_client->message.overflowed) { SV_DropClient (true); host_client->message.overflowed = false; continue; } if (host_client->message.cursize || host_client->dropasap) { if (!NET_CanSendMessage (host_client->netconnection)) { // I_Printf ("can't write\n"); continue; } if (host_client->dropasap) SV_DropClient (false); // went to another level else { if (NET_SendMessage (host_client->netconnection , &host_client->message) == -1) SV_DropClient (true); // if the message couldn't send, kick off SZ_Clear (&host_client->message); host_client->last_message = realtime; host_client->sendsignon = false; } } } // clear muzzle flashes SV_CleanupEnts (); } /* ============================================================================== SERVER SPAWNING ============================================================================== */ /* ================ SV_ModelIndex ================ */ int SV_ModelIndex (const char *name) { int i; if (!name || !name[0]) return 0; for (i=0 ; i<MAX_MODELS && sv.model_precache[i] ; i++) if (!strcmp(sv.model_precache[i], name)) return i; if (i==MAX_MODELS || !sv.model_precache[i]) Sys_Error ("SV_ModelIndex: model %s not precached", name); return i; } /* ================ SV_CreateBaseline ================ */ void SV_CreateBaseline (void) { int i; edict_t *svent; int entnum; int bits; //johnfitz -- PROTOCOL_FITZQUAKE for (entnum = 0; entnum < sv.num_edicts ; entnum++) { // get the current server version svent = EDICT_NUM(entnum); if (svent->free) continue; if (entnum > svs.maxclients && !svent->v.modelindex) continue; // // create entity baseline // VectorCopy (svent->v.origin, svent->baseline.origin); VectorCopy (svent->v.angles, svent->baseline.angles); svent->baseline.frame = svent->v.frame; svent->baseline.skin = svent->v.skin; if (entnum > 0 && entnum <= svs.maxclients) { svent->baseline.colormap = entnum; svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); svent->baseline.alpha = ENTALPHA_DEFAULT; //johnfitz -- alpha support } else { svent->baseline.colormap = 0; svent->baseline.modelindex = SV_ModelIndex(PR_GetString(svent->v.model)); svent->baseline.alpha = svent->alpha; //johnfitz -- alpha support } //johnfitz -- PROTOCOL_FITZQUAKE bits = 0; if (sv.protocol == PROTOCOL_NETQUAKE) //still want to send baseline in PROTOCOL_NETQUAKE, so reset these values { if (svent->baseline.modelindex & 0xFF00) svent->baseline.modelindex = 0; if (svent->baseline.frame & 0xFF00) svent->baseline.frame = 0; svent->baseline.alpha = ENTALPHA_DEFAULT; } else //decide which extra data needs to be sent { if (svent->baseline.modelindex & 0xFF00) bits |= B_LARGEMODEL; if (svent->baseline.frame & 0xFF00) bits |= B_LARGEFRAME; if (svent->baseline.alpha != ENTALPHA_DEFAULT) bits |= B_ALPHA; } //johnfitz // // add to the message // //johnfitz -- PROTOCOL_FITZQUAKE if (bits) MSG_WriteByte (&sv.signon, svc_spawnbaseline2); else MSG_WriteByte (&sv.signon, svc_spawnbaseline); //johnfitz MSG_WriteShort (&sv.signon,entnum); //johnfitz -- PROTOCOL_FITZQUAKE if (bits) MSG_WriteByte (&sv.signon, bits); if (bits & B_LARGEMODEL) MSG_WriteShort (&sv.signon, svent->baseline.modelindex); else MSG_WriteByte (&sv.signon, svent->baseline.modelindex); if (bits & B_LARGEFRAME) MSG_WriteShort (&sv.signon, svent->baseline.frame); else MSG_WriteByte (&sv.signon, svent->baseline.frame); //johnfitz MSG_WriteByte (&sv.signon, svent->baseline.colormap); MSG_WriteByte (&sv.signon, svent->baseline.skin); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); } //johnfitz -- PROTOCOL_FITZQUAKE if (bits & B_ALPHA) MSG_WriteByte (&sv.signon, svent->baseline.alpha); //johnfitz } } /* ================ SV_SendReconnect Tell all the clients that the server is changing levels ================ */ void SV_SendReconnect (void) { byte data[128]; sizebuf_t msg; msg.data = data; msg.cursize = 0; msg.maxsize = sizeof(data); MSG_WriteChar (&msg, svc_stufftext); MSG_WriteString (&msg, "reconnect\n"); NET_SendToAll (&msg, 5.0); if (!isDedicated) Cmd_ExecuteString ("reconnect\n", src_command); } /* ================ SV_SaveSpawnparms Grabs the current state of each client for saving across the transition to another level ================ */ void SV_SaveSpawnparms (void) { int i, j; svs.serverflags = pr_global_struct->serverflags; for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) { if (!host_client->active) continue; // call the progs to get default spawn parms for the new client pr_global_struct->self = EDICT_TO_PROG(host_client->edict); PR_ExecuteProgram (pr_global_struct->SetChangeParms); for (j=0 ; j<NUM_SPAWN_PARMS ; j++) host_client->spawn_parms[j] = (&pr_global_struct->parm1)[j]; } } /* ================ SV_SpawnServer This is called at the start of each level ================ */ extern float scr_centertime_off; void SV_SpawnServer (const char *server) { static char dummy[8] = { 0,0,0,0,0,0,0,0 }; edict_t *ent; int i; // let's not have any servers with no name if (hostname.string[0] == 0) Cvar_Set ("hostname", "UNNAMED"); scr_centertime_off = 0; Con_DPrintf ("SpawnServer: %s\n",server); svs.changelevel_issued = false; // now safe to issue another // // tell all connected clients that we are going to a new level // if (sv.active) { SV_SendReconnect (); } // // make cvars consistant // if (coop.value) Cvar_Set ("deathmatch", "0"); current_skill = (int)(skill.value + 0.5); if (current_skill < 0) current_skill = 0; if (current_skill > 3) current_skill = 3; Cvar_SetValue ("skill", (float)current_skill); // // set up the new server // //memset (&sv, 0, sizeof(sv)); Host_ClearMemory (); q_strlcpy (sv.name, server, sizeof(sv.name)); sv.protocol = sv_protocol; // johnfitz // load progs to get entity field count PR_LoadProgs (); // allocate server memory /* Host_ClearMemory() called above already cleared the whole sv structure */ sv.max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS); //johnfitz -- max_edicts cvar sv.edicts = (edict_t *) Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts"); sv.datagram.maxsize = sizeof(sv.datagram_buf); sv.datagram.cursize = 0; sv.datagram.data = sv.datagram_buf; sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); sv.reliable_datagram.cursize = 0; sv.reliable_datagram.data = sv.reliable_datagram_buf; sv.signon.maxsize = sizeof(sv.signon_buf); sv.signon.cursize = 0; sv.signon.data = sv.signon_buf; // leave slots at start for clients only sv.num_edicts = svs.maxclients+1; for (i=0 ; i<svs.maxclients ; i++) { ent = EDICT_NUM(i+1); svs.clients[i].edict = ent; } sv.state = ss_loading; sv.paused = false; sv.time = 1.0; q_strlcpy (sv.name, server, sizeof(sv.name)); q_snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", server); sv.worldmodel = Mod_ForName (sv.modelname, false); if (!sv.worldmodel) { Con_Printf ("Couldn't spawn server %s\n", sv.modelname); sv.active = false; return; } sv.models[1] = sv.worldmodel; // // clear world interaction links // SV_ClearWorld (); sv.sound_precache[0] = dummy; sv.model_precache[0] = dummy; sv.model_precache[1] = sv.modelname; for (i=1 ; i<sv.worldmodel->numsubmodels ; i++) { sv.model_precache[1+i] = localmodels[i]; sv.models[i+1] = Mod_ForName (localmodels[i], false); } // // load the rest of the entities // ent = EDICT_NUM(0); memset (&ent->v, 0, progs->entityfields * 4); ent->free = false; ent->v.model = PR_SetEngineString(sv.worldmodel->name); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; if (coop.value) pr_global_struct->coop = coop.value; else pr_global_struct->deathmatch = deathmatch.value; pr_global_struct->mapname = PR_SetEngineString(sv.name); // serverflags are for cross level information (sigils) pr_global_struct->serverflags = svs.serverflags; ED_LoadFromFile (sv.worldmodel->entities); sv.active = true; // all setup is completed, any further precache statements are errors sv.state = ss_active; // run two frames to allow everything to settle host_frametime = 0.1; SV_Physics (); SV_Physics (); // create a baseline for more efficient communications SV_CreateBaseline (); //johnfitz -- warn if signon buffer larger than standard server can handle if (sv.signon.cursize > 8000-2) //max size that will fit into 8000-sized client->message buffer with 2 extra bytes on the end Con_DWarning ("%i byte signon buffer exceeds standard limit of 7998.\n", sv.signon.cursize); //johnfitz // send serverinfo to all connected clients for (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) if (host_client->active) SV_SendServerinfo (host_client); Con_DPrintf ("Server spawned.\n"); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/r_sprite.c������������������������������������������������������������������0000644�0000000�0000000�00000011536�12571117266�015530� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //r_sprite.c -- sprite model rendering #include "quakedef.h" /* ================ R_GetSpriteFrame ================ */ mspriteframe_t *R_GetSpriteFrame (entity_t *currentent) { msprite_t *psprite; mspritegroup_t *pspritegroup; mspriteframe_t *pspriteframe; int i, numframes, frame; float *pintervals, fullinterval, targettime, time; psprite = (msprite_t *) currentent->model->cache.data; frame = currentent->frame; if ((frame >= psprite->numframes) || (frame < 0)) { Con_DPrintf ("R_DrawSprite: no such frame %d for '%s'\n", frame, currentent->model->name); frame = 0; } if (psprite->frames[frame].type == SPR_SINGLE) { pspriteframe = psprite->frames[frame].frameptr; } else { pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; pintervals = pspritegroup->intervals; numframes = pspritegroup->numframes; fullinterval = pintervals[numframes-1]; time = cl.time + currentent->syncbase; // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values // are positive, so we don't have to worry about division by 0 targettime = time - ((int)(time / fullinterval)) * fullinterval; for (i=0 ; i<(numframes-1) ; i++) { if (pintervals[i] > targettime) break; } pspriteframe = pspritegroup->frames[i]; } return pspriteframe; } /* ================= R_DrawSpriteModel -- johnfitz -- rewritten: now supports all orientations ================= */ void R_DrawSpriteModel (entity_t *e) { vec3_t point, v_forward, v_right, v_up; msprite_t *psprite; mspriteframe_t *frame; float *s_up, *s_right; float angle, sr, cr; //TODO: frustum cull it? frame = R_GetSpriteFrame (e); psprite = (msprite_t *) currententity->model->cache.data; switch(psprite->type) { case SPR_VP_PARALLEL_UPRIGHT: //faces view plane, up is towards the heavens v_up[0] = 0; v_up[1] = 0; v_up[2] = 1; s_up = v_up; s_right = vright; break; case SPR_FACING_UPRIGHT: //faces camera origin, up is towards the heavens VectorSubtract(currententity->origin, r_origin, v_forward); v_forward[2] = 0; VectorNormalizeFast(v_forward); v_right[0] = v_forward[1]; v_right[1] = -v_forward[0]; v_right[2] = 0; v_up[0] = 0; v_up[1] = 0; v_up[2] = 1; s_up = v_up; s_right = v_right; break; case SPR_VP_PARALLEL: //faces view plane, up is towards the top of the screen s_up = vup; s_right = vright; break; case SPR_ORIENTED: //pitch yaw roll are independent of camera AngleVectors (currententity->angles, v_forward, v_right, v_up); s_up = v_up; s_right = v_right; break; case SPR_VP_PARALLEL_ORIENTED: //faces view plane, but obeys roll value angle = currententity->angles[ROLL] * M_PI_DIV_180; sr = sin(angle); cr = cos(angle); v_right[0] = vright[0] * cr + vup[0] * sr; v_right[1] = vright[1] * cr + vup[1] * sr; v_right[2] = vright[2] * cr + vup[2] * sr; v_up[0] = vright[0] * -sr + vup[0] * cr; v_up[1] = vright[1] * -sr + vup[1] * cr; v_up[2] = vright[2] * -sr + vup[2] * cr; s_up = v_up; s_right = v_right; break; default: return; } //johnfitz: offset decals if (psprite->type == SPR_ORIENTED) GL_PolygonOffset (OFFSET_DECAL); glColor3f (1,1,1); GL_DisableMultitexture(); GL_Bind(frame->gltexture); glEnable (GL_ALPHA_TEST); glBegin (GL_TRIANGLE_FAN); //was GL_QUADS, but changed to support r_showtris glTexCoord2f (0, frame->tmax); VectorMA (e->origin, frame->down, s_up, point); VectorMA (point, frame->left, s_right, point); glVertex3fv (point); glTexCoord2f (0, 0); VectorMA (e->origin, frame->up, s_up, point); VectorMA (point, frame->left, s_right, point); glVertex3fv (point); glTexCoord2f (frame->smax, 0); VectorMA (e->origin, frame->up, s_up, point); VectorMA (point, frame->right, s_right, point); glVertex3fv (point); glTexCoord2f (frame->smax, frame->tmax); VectorMA (e->origin, frame->down, s_up, point); VectorMA (point, frame->right, s_right, point); glVertex3fv (point); glEnd (); glDisable (GL_ALPHA_TEST); //johnfitz: offset decals if (psprite->type == SPR_ORIENTED) GL_PolygonOffset (OFFSET_NONE); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_opus.h������������������������������������������������������������������0000644�0000000�0000000�00000000323�12171711457�015526� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Ogg/Opus streaming music support. */ #if !defined(_SND_OPUS_H_) #define _SND_OPUS_H_ 1 #if defined(USE_CODEC_OPUS) extern snd_codec_t opus_codec; #endif /* USE_CODEC_OPUS */ #endif /* ! _SND_OPUS_H_ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_mp3.c�������������������������������������������������������������������0000644�0000000�0000000�00000036541�12550656216�015247� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * MP3 decoding support using libmad: Adapted from the SoX library at * http://sourceforge.net/projects/sox/, LGPLv2, Copyright (c) 2007-2009 * SoX contributors, written by Fabrizio Gennari <fabrizio.ge@tiscali.it>, * with the decoding part based on the decoder tutorial program madlld * written by Bertrand Petit <madlld@phoe.fmug.org> (BSD license, see at * http://www.bsd-dk.dk/~elrond/audio/madlld/). The tag identification * functions were adapted from the GPL-licensed libid3tag library, see at * http://www.underbit.com/products/mad/. Adapted to Quake and Hexen II * game engines by O.Sezer : * Copyright (C) 2010-2015 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #include "quakedef.h" #if defined(USE_CODEC_MP3) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_mp3.h" #include <mad.h> #define ID3_TAG_FLAG_FOOTERPRESENT 0x10 /* Under Windows, importing data from DLLs is a dicey proposition. This is true * when using dlopen, but also true if linking directly against the DLL if the * header does not mark the data as __declspec(dllexport), which mad.h does not. * Sidestep the issue by defining our own mad_timer_zero. This is needed because * mad_timer_zero is used in some of the mad.h macros. */ #define mad_timer_zero mad_timer_zero_stub static mad_timer_t const mad_timer_zero_stub = {0, 0}; /* MAD returns values with MAD_F_FRACBITS (28) bits of precision, though it's not certain that all of them are meaningful. Default to 16 bits to align with most users expectation of output file should be 16 bits. */ #define MP3_MAD_SAMPLEBITS 16 #define MP3_MAD_SAMPLEWIDTH 2 #define MP3_BUFFER_SIZE (5 * 8192) /* Private data */ typedef struct _mp3_priv_t { unsigned char mp3_buffer[MP3_BUFFER_SIZE]; struct mad_stream Stream; struct mad_frame Frame; struct mad_synth Synth; mad_timer_t Timer; ptrdiff_t cursamp; size_t FrameCount; } mp3_priv_t; /* This function merges the functions tagtype() and id3_tag_query() * from MAD's libid3tag, so we don't have to link to it * Returns 0 if the frame is not an ID3 tag, tag length if it is */ static inline qboolean tag_is_id3v1(const unsigned char *data, size_t length) { if (length >= 3 && data[0] == 'T' && data[1] == 'A' && data[2] == 'G') { return true; } return false; } static inline qboolean tag_is_id3v2(const unsigned char *data, size_t length) { if (length >= 10 && (data[0] == 'I' && data[1] == 'D' && data[2] == '3') && data[3] < 0xff && data[4] < 0xff && data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) { return true; } return false; } /* http://wiki.hydrogenaud.io/index.php?title=APEv1_specification * http://wiki.hydrogenaud.io/index.php?title=APEv2_specification * Detect an APEv2 tag. (APEv1 has no header, so no luck.) */ static inline qboolean tag_is_apetag(const unsigned char *data, size_t length) { unsigned int v; if (length < 32) return false; if (memcmp(data,"APETAGEX",8) != 0) return false; v = (data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]; if (v != 2000U/* && v != 1000U*/) return false; v = 0; if (memcmp(&data[24],&v,4) != 0 || memcmp(&data[28],&v,4) != 0) return false; return true; } static size_t mp3_tagsize(const unsigned char *data, size_t length) { size_t size; if (tag_is_id3v1(data, length)) return 128; if (tag_is_id3v2(data, length)) { unsigned char flags = data[5]; size = 10 + (data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]; if (flags & ID3_TAG_FLAG_FOOTERPRESENT) size += 10; for ( ; size < length && !data[size]; ++size) ; /* Consume padding */ return size; } if (tag_is_apetag(data, length)) { size = (data[15]<<24) | (data[14]<<16) | (data[13]<<8) | data[12]; size += 32; return size; } return 0; } /* Attempts to read an ID3 tag at the current location in stream and * consume it all. Returns -1 if no tag is found. Its up to caller * to recover. */ static int mp3_inputtag(snd_stream_t *stream) { mp3_priv_t *p = (mp3_priv_t *) stream->priv; int rc = -1; size_t remaining; size_t tagsize; /* FIXME: This needs some more work if we are to ever * look at the ID3 frame. This is because the Stream * may not be able to hold the complete ID3 frame. * We should consume the whole frame inside tagtype() * instead of outside of tagframe(). That would support * recovering when Stream contains less then 8-bytes (header) * and also when ID3v2 is bigger then Stream buffer size. * Need to pass in stream so that buffer can be * consumed as well as letting additional data to be * read in. */ remaining = p->Stream.bufend - p->Stream.next_frame; tagsize = mp3_tagsize(p->Stream.this_frame, remaining); if (tagsize != 0) { mad_stream_skip(&p->Stream, tagsize); rc = 0; } /* We know that a valid frame hasn't been found yet * so help libmad out and go back into frame seek mode. * This is true whether an ID3 tag was found or not. */ mad_stream_sync(&p->Stream); return rc; } /* (Re)fill the stream buffer that is to be decoded. If any data * still exists in the buffer then they are first shifted to be * front of the stream buffer. */ static int mp3_inputdata(snd_stream_t *stream) { mp3_priv_t *p = (mp3_priv_t *) stream->priv; size_t bytes_read; size_t remaining; remaining = p->Stream.bufend - p->Stream.next_frame; /* libmad does not consume all the buffer it's given. Some * data, part of a truncated frame, is left unused at the * end of the buffer. That data must be put back at the * beginning of the buffer and taken in account for * refilling the buffer. This means that the input buffer * must be large enough to hold a complete frame at the * highest observable bit-rate (currently 448 kb/s). * TODO: Is 2016 bytes the size of the largest frame? * (448000*(1152/32000))/8 */ memmove(p->mp3_buffer, p->Stream.next_frame, remaining); bytes_read = FS_fread(p->mp3_buffer + remaining, 1, MP3_BUFFER_SIZE - remaining, &stream->fh); if (bytes_read == 0) return -1; mad_stream_buffer(&p->Stream, p->mp3_buffer, bytes_read+remaining); p->Stream.error = MAD_ERROR_NONE; return 0; } static int mp3_startread(snd_stream_t *stream) { mp3_priv_t *p = (mp3_priv_t *) stream->priv; size_t ReadSize; mad_stream_init(&p->Stream); mad_frame_init(&p->Frame); mad_synth_init(&p->Synth); mad_timer_reset(&p->Timer); /* Decode at least one valid frame to find out the input * format. The decoded frame will be saved off so that it * can be processed later. */ ReadSize = FS_fread(p->mp3_buffer, 1, MP3_BUFFER_SIZE, &stream->fh); if (!ReadSize || FS_ferror(&stream->fh)) return -1; mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); /* Find a valid frame before starting up. This makes sure * that we have a valid MP3 and also skips past ID3v2 tags * at the beginning of the audio file. */ p->Stream.error = MAD_ERROR_NONE; while (mad_frame_decode(&p->Frame,&p->Stream)) { /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (mp3_inputdata(stream) == -1) return -1;/* EOF with no valid data */ continue; } /* Consume any ID3 tags */ mp3_inputtag(stream); /* FIXME: We should probably detect when we've read * a bunch of non-ID3 data and still haven't found a * frame. In that case we can abort early without * scanning the whole file. */ p->Stream.error = MAD_ERROR_NONE; } if (p->Stream.error) { Con_Printf("MP3: No valid MP3 frame found\n"); return -1; } switch(p->Frame.header.mode) { case MAD_MODE_SINGLE_CHANNEL: case MAD_MODE_DUAL_CHANNEL: case MAD_MODE_JOINT_STEREO: case MAD_MODE_STEREO: stream->info.channels = MAD_NCHANNELS(&p->Frame.header); break; default: Con_Printf("MP3: Cannot determine number of channels\n"); return -1; } p->FrameCount = 1; mad_timer_add(&p->Timer,p->Frame.header.duration); mad_synth_frame(&p->Synth,&p->Frame); stream->info.rate = p->Synth.pcm.samplerate; stream->info.bits = MP3_MAD_SAMPLEBITS; stream->info.width = MP3_MAD_SAMPLEWIDTH; p->cursamp = 0; return 0; } /* Read up to len samples from p->Synth * If needed, read some more MP3 data, decode them and synth them * Place in buf[]. * Return number of samples read. */ static int mp3_decode(snd_stream_t *stream, byte *buf, int len) { mp3_priv_t *p = (mp3_priv_t *) stream->priv; int donow, i, done = 0; mad_fixed_t sample; int chan, x; do { x = (p->Synth.pcm.length - p->cursamp) * stream->info.channels; donow = q_min(len, x); i = 0; while (i < donow) { for (chan = 0; chan < stream->info.channels; chan++) { sample = p->Synth.pcm.samples[chan][p->cursamp]; /* convert from fixed to short, * write in host-endian format. */ if (sample <= -MAD_F_ONE) sample = -0x7FFF; else if (sample >= MAD_F_ONE) sample = 0x7FFF; else sample >>= (MAD_F_FRACBITS + 1 - 16); if (host_bigendian) { *buf++ = (sample >> 8) & 0xFF; *buf++ = sample & 0xFF; } else /* assumed LITTLE_ENDIAN. */ { *buf++ = sample & 0xFF; *buf++ = (sample >> 8) & 0xFF; } i++; } p->cursamp++; } len -= donow; done += donow; if (len == 0) break; /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (mp3_inputdata(stream) == -1) { /* check feof() ?? */ Con_DPrintf("mp3 EOF\n"); break; } } if (mad_frame_decode(&p->Frame, &p->Stream)) { if (MAD_RECOVERABLE(p->Stream.error)) { mp3_inputtag(stream); continue; } else { if (p->Stream.error == MAD_ERROR_BUFLEN) continue; else { Con_Printf("MP3: unrecoverable frame level error (%s)\n", mad_stream_errorstr(&p->Stream)); break; } } } p->FrameCount++; mad_timer_add(&p->Timer, p->Frame.header.duration); mad_synth_frame(&p->Synth, &p->Frame); p->cursamp = 0; } while (1); return done; } static int mp3_stopread(snd_stream_t *stream) { mp3_priv_t *p = (mp3_priv_t*) stream->priv; mad_synth_finish(&p->Synth); mad_frame_finish(&p->Frame); mad_stream_finish(&p->Stream); return 0; } static int mp3_madseek(snd_stream_t *stream, unsigned long offset) { mp3_priv_t *p = (mp3_priv_t *) stream->priv; size_t initial_bitrate = p->Frame.header.bitrate; size_t tagsize = 0, consumed = 0; int vbr = 0; /* Variable Bit Rate, bool */ qboolean depadded = false; unsigned long to_skip_samples = 0; /* Reset all */ FS_rewind(&stream->fh); mad_timer_reset(&p->Timer); p->FrameCount = 0; /* They where opened in startread */ mad_synth_finish(&p->Synth); mad_frame_finish(&p->Frame); mad_stream_finish(&p->Stream); mad_stream_init(&p->Stream); mad_frame_init(&p->Frame); mad_synth_init(&p->Synth); offset /= stream->info.channels; to_skip_samples = offset; while (1) /* Read data from the MP3 file */ { int bytes_read, padding = 0; size_t leftover = p->Stream.bufend - p->Stream.next_frame; memcpy(p->mp3_buffer, p->Stream.this_frame, leftover); bytes_read = FS_fread(p->mp3_buffer + leftover, (size_t) 1, MP3_BUFFER_SIZE - leftover, &stream->fh); if (bytes_read <= 0) { Con_DPrintf("seek failure. unexpected EOF (frames=%lu leftover=%lu)\n", (unsigned long)p->FrameCount, (unsigned long)leftover); break; } for ( ; !depadded && padding < bytes_read && !p->mp3_buffer[padding]; ++padding) ; depadded = true; mad_stream_buffer(&p->Stream, p->mp3_buffer + padding, leftover + bytes_read - padding); while (1) /* Decode frame headers */ { static unsigned short samples; p->Stream.error = MAD_ERROR_NONE; /* Not an audio frame */ if (mad_header_decode(&p->Frame.header, &p->Stream) == -1) { if (p->Stream.error == MAD_ERROR_BUFLEN) break; /* Normal behaviour; get some more data from the file */ if (!MAD_RECOVERABLE(p->Stream.error)) { Con_DPrintf("unrecoverable MAD error\n"); break; } if (p->Stream.error == MAD_ERROR_LOSTSYNC) { unsigned long available = (p->Stream.bufend - p->Stream.this_frame); tagsize = mp3_tagsize(p->Stream.this_frame, (size_t) available); if (tagsize) { /* It's some ID3 tags, so just skip */ if (tagsize >= available) { FS_fseek(&stream->fh, (long)(tagsize - available), SEEK_CUR); depadded = false; } mad_stream_skip(&p->Stream, q_min(tagsize, available)); } else { Con_DPrintf("MAD lost sync\n"); } } else { Con_DPrintf("recoverable MAD error\n"); } continue; } consumed += p->Stream.next_frame - p->Stream.this_frame; vbr |= (p->Frame.header.bitrate != initial_bitrate); samples = 32 * MAD_NSBSAMPLES(&p->Frame.header); p->FrameCount++; mad_timer_add(&p->Timer, p->Frame.header.duration); if (to_skip_samples <= samples) { mad_frame_decode(&p->Frame,&p->Stream); mad_synth_frame(&p->Synth, &p->Frame); p->cursamp = to_skip_samples; return 0; } else to_skip_samples -= samples; /* If not VBR, we can extrapolate frame size */ if (p->FrameCount == 64 && !vbr) { p->FrameCount = offset / samples; to_skip_samples = offset % samples; if (0 != FS_fseek(&stream->fh, (p->FrameCount * consumed / 64) + tagsize, SEEK_SET)) return -1; /* Reset Stream for refilling buffer */ mad_stream_finish(&p->Stream); mad_stream_init(&p->Stream); break; } } } return -1; } static qboolean S_MP3_CodecInitialize (void) { return true; } static void S_MP3_CodecShutdown (void) { } static qboolean S_MP3_CodecOpenStream (snd_stream_t *stream) { int err; stream->priv = calloc(1, sizeof(mp3_priv_t)); if (!stream->priv) { Con_Printf("Insufficient memory for MP3 audio\n"); return false; } err = mp3_startread(stream); if (err != 0) { Con_Printf("%s is not a valid mp3 file\n", stream->name); } else if (stream->info.channels != 1 && stream->info.channels != 2) { Con_Printf("Unsupported number of channels %d in %s\n", stream->info.channels, stream->name); } else { return true; } free(stream->priv); return false; } static int S_MP3_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) { int res = mp3_decode(stream, (byte *)buffer, bytes / stream->info.width); return res * stream->info.width; } static void S_MP3_CodecCloseStream (snd_stream_t *stream) { mp3_stopread(stream); free(stream->priv); S_CodecUtilClose(&stream); } static int S_MP3_CodecRewindStream (snd_stream_t *stream) { /* mp3_stopread(stream); FS_rewind(&stream->fh); return mp3_startread(stream); */ return mp3_madseek(stream, 0); } snd_codec_t mp3_codec = { CODECTYPE_MP3, true, /* always available. */ "mp3", S_MP3_CodecInitialize, S_MP3_CodecShutdown, S_MP3_CodecOpenStream, S_MP3_CodecReadStream, S_MP3_CodecRewindStream, S_MP3_CodecCloseStream, NULL }; #endif /* USE_CODEC_MP3 */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/bgmusic.h�������������������������������������������������������������������0000644�0000000�0000000�00000002504�12113434521�015316� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Background music handling for Quakespasm (adapted from uHexen2) * Handles streaming music as raw sound samples and runs the midi driver * * Copyright (C) 1999-2005 Id Software, Inc. * Copyright (C) 2010-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #ifndef _BGMUSIC_H_ #define _BGMUSIC_H_ extern qboolean bgmloop; extern cvar_t bgm_extmusic; qboolean BGM_Init (void); void BGM_Shutdown (void); void BGM_Play (const char *filename); void BGM_Stop (void); void BGM_Update (void); void BGM_Pause (void); void BGM_Resume (void); void BGM_PlayCDtrack (byte track, qboolean looping); #endif /* _BGMUSIC_H_ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_wipx.h������������������������������������������������������������������0000644�0000000�0000000�00000003553�12407762022�015535� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __NET_WINIPX_H #define __NET_WINIPX_H sys_socket_t WIPX_Init (void); void WIPX_Shutdown (void); void WIPX_Listen (qboolean state); sys_socket_t WIPX_OpenSocket (int port); int WIPX_CloseSocket (sys_socket_t socketid); int WIPX_Connect (sys_socket_t socketid, struct qsockaddr *addr); sys_socket_t WIPX_CheckNewConnections (void); int WIPX_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr); int WIPX_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr); int WIPX_Broadcast (sys_socket_t socketid, byte *buf, int len); const char *WIPX_AddrToString (struct qsockaddr *addr); int WIPX_StringToAddr (const char *string, struct qsockaddr *addr); int WIPX_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr); int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name); int WIPX_GetAddrFromName (const char *name, struct qsockaddr *addr); int WIPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); int WIPX_GetSocketPort (struct qsockaddr *addr); int WIPX_SetSocketPort (struct qsockaddr *addr, int port); #endif /* __NET_WINIPX_H */ �����������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/detect.sh�������������������������������������������������������������������0000755�0000000�0000000�00000001453�12013076135�015327� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh # script from loki_setup tools DetectARCH() { status=1 case `uname -m` in amd64 | x86_64) echo "x86_64" status=0;; i?86 | i86*) echo "x86" status=0;; 90*/*) echo "hppa" status=0;; *) case `uname -s` in IRIX*) echo "mips" status=0;; AIX*) echo "ppc" status=0;; *) arch=`uname -p 2> /dev/null || uname -m` if test "$arch" = powerpc; then echo "ppc" else echo $arch fi status=0;; esac esac return $status } DetectOS() { os=`uname -s` if test "$os" = "OpenUNIX"; then echo SCO_SV else echo $os fi return 0 } if test "$1" = "os"; then result=`DetectOS` elif test "$1" = "arch"; then result=`DetectARCH` else result="OS: `DetectOS`, Arch: `DetectARCH`" fi status="$?" echo $result exit $status ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/pl_linux.c������������������������������������������������������������������0000644�0000000�0000000�00000004522�12407762022�015522� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif static const Uint8 bmp_bytes[] = { #include "qs_bmp.h" }; void PL_SetWindowIcon (void) { SDL_RWops *rwop; SDL_Surface *icon; Uint32 colorkey; /* SDL_RWFromConstMem() requires SDL >= 1.2.7 */ rwop = SDL_RWFromConstMem(bmp_bytes, sizeof(bmp_bytes)); if (rwop == NULL) return; icon = SDL_LoadBMP_RW(rwop, 1); if (icon == NULL) return; /* make pure magenta (#ff00ff) tranparent */ colorkey = SDL_MapRGB(icon->format, 255, 0, 255); #if defined(USE_SDL2) SDL_SetColorKey(icon, SDL_TRUE, colorkey); SDL_SetWindowIcon((SDL_Window*) VID_GetWindow(), icon); #else SDL_SetColorKey(icon, SDL_SRCCOLORKEY, colorkey); SDL_WM_SetIcon(icon, NULL); #endif SDL_FreeSurface(icon); } void PL_VID_Shutdown (void) { } #define MAX_CLIPBOARDTXT MAXCMDLINE /* 256 */ char *PL_GetClipboardData (void) { char *data = NULL; #if defined(USE_SDL2) char *cliptext = SDL_GetClipboardText(); if (cliptext != NULL) { size_t size = strlen(cliptext) + 1; /* this is intended for simple small text copies * such as an ip address, etc: do chop the size * here, otherwise we may experience Z_Malloc() * failures and all other not-oh-so-fun stuff. */ size = q_min(MAX_CLIPBOARDTXT, size); data = (char *) Z_Malloc(size); q_strlcpy (data, cliptext, size); } #endif return data; } void PL_ErrorDialog (const char *errorMsg) { } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/wad.h�����������������������������������������������������������������������0000644�0000000�0000000�00000003766�12407762022�014461� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_WAD_H #define _QUAKE_WAD_H //=============== // TYPES //=============== #define CMP_NONE 0 #define CMP_LZSS 1 #define TYP_NONE 0 #define TYP_LABEL 1 #define TYP_LUMPY 64 // 64 + grab command number #define TYP_PALETTE 64 #define TYP_QTEX 65 #define TYP_QPIC 66 #define TYP_SOUND 67 #define TYP_MIPTEX 68 #define WADFILENAME "gfx.wad" //johnfitz -- filename is now hard-coded for honesty typedef struct { int width, height; byte data[4]; // variably sized } qpic_t; typedef struct { char identification[4]; // should be WAD2 or 2DAW int numlumps; int infotableofs; } wadinfo_t; typedef struct { int filepos; int disksize; int size; // uncompressed char type; char compression; char pad1, pad2; char name[16]; // must be null terminated } lumpinfo_t; extern int wad_numlumps; extern lumpinfo_t *wad_lumps; extern byte *wad_base; void W_LoadWadFile (void); //johnfitz -- filename is now hard-coded for honesty void W_CleanupName (const char *in, char *out); lumpinfo_t *W_GetLumpinfo (const char *name); void *W_GetLumpName (const char *name); void *W_GetLumpNum (int num); void SwapPic (qpic_t *pic); #endif /* _QUAKE_WAD_H */ ����������quakespasm-0.91.0/Quake/gl_refrag.c�����������������������������������������������������������������0000644�0000000�0000000�00000011171�12530477523�015624� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // r_efrag.c #include "quakedef.h" mnode_t *r_pefragtopnode; //=========================================================================== /* =============================================================================== ENTITY FRAGMENT FUNCTIONS =============================================================================== */ efrag_t **lastlink; vec3_t r_emins, r_emaxs; entity_t *r_addent; /* ================ R_RemoveEfrags Call when removing an object from the world or moving it to another position ================ */ void R_RemoveEfrags (entity_t *ent) { efrag_t *ef, *old, *walk, **prev; ef = ent->efrag; while (ef) { prev = &ef->leaf->efrags; while (1) { walk = *prev; if (!walk) break; if (walk == ef) { // remove this fragment *prev = ef->leafnext; break; } else prev = &walk->leafnext; } old = ef; ef = ef->entnext; // put it on the free list old->entnext = cl.free_efrags; cl.free_efrags = old; } ent->efrag = NULL; } /* =================== R_SplitEntityOnNode =================== */ void R_SplitEntityOnNode (mnode_t *node) { efrag_t *ef; mplane_t *splitplane; mleaf_t *leaf; int sides; if (node->contents == CONTENTS_SOLID) { return; } // add an efrag if the node is a leaf if ( node->contents < 0) { if (!r_pefragtopnode) r_pefragtopnode = node; leaf = (mleaf_t *)node; // grab an efrag off the free list ef = cl.free_efrags; if (!ef) { //johnfitz -- less spammy overflow message if (!dev_overflows.efrags || dev_overflows.efrags + CONSOLE_RESPAM_TIME < realtime ) { Con_Printf ("Too many efrags!\n"); dev_overflows.efrags = realtime; } //johnfitz return; // no free fragments... } cl.free_efrags = cl.free_efrags->entnext; ef->entity = r_addent; // add the entity link *lastlink = ef; lastlink = &ef->entnext; ef->entnext = NULL; // set the leaf links ef->leaf = leaf; ef->leafnext = leaf->efrags; leaf->efrags = ef; return; } // NODE_MIXED splitplane = node->plane; sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane); if (sides == 3) { // split on this plane // if this is the first splitter of this bmodel, remember it if (!r_pefragtopnode) r_pefragtopnode = node; } // recurse down the contacted sides if (sides & 1) R_SplitEntityOnNode (node->children[0]); if (sides & 2) R_SplitEntityOnNode (node->children[1]); } /* =========== R_CheckEfrags -- johnfitz -- check for excessive efrag count =========== */ void R_CheckEfrags (void) { efrag_t *ef; int count; if (cls.signon < 2) return; //don't spam when still parsing signon packet full of static ents for (count=MAX_EFRAGS, ef = cl.free_efrags; ef; count--, ef = ef->entnext) ; if (count > 640 && dev_peakstats.efrags <= 640) Con_DWarning ("%i efrags exceeds standard limit of 640.\n", count); dev_stats.efrags = count; dev_peakstats.efrags = q_max(count, dev_peakstats.efrags); } /* =========== R_AddEfrags =========== */ void R_AddEfrags (entity_t *ent) { qmodel_t *entmodel; int i; if (!ent->model) return; r_addent = ent; lastlink = &ent->efrag; r_pefragtopnode = NULL; entmodel = ent->model; for (i=0 ; i<3 ; i++) { r_emins[i] = ent->origin[i] + entmodel->mins[i]; r_emaxs[i] = ent->origin[i] + entmodel->maxs[i]; } R_SplitEntityOnNode (cl.worldmodel->nodes); ent->topnode = r_pefragtopnode; R_CheckEfrags (); //johnfitz } /* ================ R_StoreEfrags -- johnfitz -- pointless switch statement removed. ================ */ void R_StoreEfrags (efrag_t **ppefrag) { entity_t *pent; efrag_t *pefrag; while ((pefrag = *ppefrag) != NULL) { pent = pefrag->entity; if ((pent->visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS)) { cl_visedicts[cl_numvisedicts++] = pent; pent->visframe = r_framecount; } ppefrag = &pefrag->leafnext; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/menu.h����������������������������������������������������������������������0000644�0000000�0000000�00000003327�12415301271�014635� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAKE_MENU_H #define _QUAKE_MENU_H enum m_state_e { m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_video, m_keys, m_help, m_quit, m_lanconfig, m_gameoptions, m_search, m_slist }; extern enum m_state_e m_state; extern enum m_state_e m_return_state; extern qboolean m_entersound; // // menus // void M_Init (void); void M_Keydown (int key); void M_Charinput (int key); qboolean M_TextEntry (void); void M_ToggleMenu_f (void); void M_Menu_Main_f (void); void M_Menu_Options_f (void); void M_Menu_Quit_f (void); void M_Print (int cx, int cy, const char *str); void M_PrintWhite (int cx, int cy, const char *str); void M_Draw (void); void M_DrawCharacter (int cx, int line, int num); void M_DrawPic (int x, int y, qpic_t *pic); void M_DrawTransPic (int x, int y, qpic_t *pic); void M_DrawCheckbox (int x, int y, int on); #endif /* _QUAKE_MENU_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/host_cmd.c������������������������������������������������������������������0000644�0000000�0000000�00000134607�12533475207�015506� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #ifndef _WIN32 #include <dirent.h> #endif extern cvar_t pausable; int current_skill; void Mod_Print (void); /* ================== Host_Quit_f ================== */ void Host_Quit_f (void) { if (key_dest != key_console && cls.state != ca_dedicated) { M_Menu_Quit_f (); return; } CL_Disconnect (); Host_ShutdownServer(false); Sys_Quit (); } //============================================================================== //johnfitz -- extramaps management //============================================================================== // ericw -- was extralevel_t, renamed and now used with mods list as well // to simplify completion code typedef struct filelist_item_s { char name[32]; struct filelist_item_s *next; } filelist_item_t; /* ================== FileList_Add ================== */ void FileList_Add (const char *name, filelist_item_t **list) { filelist_item_t *item,*cursor,*prev; // ignore duplicate for (item = *list; item; item = item->next) { if (!Q_strcmp (name, item->name)) return; } item = (filelist_item_t *) Z_Malloc(sizeof(filelist_item_t)); q_strlcpy (item->name, name, sizeof(item->name)); // insert each entry in alphabetical order if (*list == NULL || q_strcasecmp(item->name, (*list)->name) < 0) //insert at front { item->next = *list; *list = item; } else //insert later { prev = *list; cursor = (*list)->next; while (cursor && (q_strcasecmp(item->name, cursor->name) > 0)) { prev = cursor; cursor = cursor->next; } item->next = prev->next; prev->next = item; } } static void FileList_Clear (filelist_item_t **list) { filelist_item_t *blah; while (*list) { blah = (*list)->next; Z_Free(*list); *list = blah; } } filelist_item_t *extralevels; void ExtraMaps_Add (const char *name) { FileList_Add(name, &extralevels); } void ExtraMaps_Init (void) { #ifdef _WIN32 WIN32_FIND_DATA fdat; HANDLE fhnd; #else DIR *dir_p; struct dirent *dir_t; #endif char filestring[MAX_OSPATH]; char mapname[32]; char ignorepakdir[32]; searchpath_t *search; pack_t *pak; int i; // we don't want to list the maps in id1 pakfiles, // because these are not "add-on" levels q_snprintf (ignorepakdir, sizeof(ignorepakdir), "/%s/", GAMENAME); for (search = com_searchpaths; search; search = search->next) { if (*search->filename) //directory { #ifdef _WIN32 q_snprintf (filestring, sizeof(filestring), "%s/maps/*.bsp", search->filename); fhnd = FindFirstFile(filestring, &fdat); if (fhnd == INVALID_HANDLE_VALUE) continue; do { COM_StripExtension(fdat.cFileName, mapname, sizeof(mapname)); ExtraMaps_Add (mapname); } while (FindNextFile(fhnd, &fdat)); FindClose(fhnd); #else q_snprintf (filestring, sizeof(filestring), "%s/maps/", search->filename); dir_p = opendir(filestring); if (dir_p == NULL) continue; while ((dir_t = readdir(dir_p)) != NULL) { if (q_strcasecmp(COM_FileGetExtension(dir_t->d_name), "bsp") != 0) continue; COM_StripExtension(dir_t->d_name, mapname, sizeof(mapname)); ExtraMaps_Add (mapname); } closedir(dir_p); #endif } else //pakfile { if (!strstr(search->pack->filename, ignorepakdir)) { //don't list standard id maps for (i = 0, pak = search->pack; i < pak->numfiles; i++) { if (!strcmp(COM_FileGetExtension(pak->files[i].name), "bsp")) { if (pak->files[i].filelen > 32*1024) { // don't list files under 32k (ammo boxes etc) COM_StripExtension(pak->files[i].name + 5, mapname, sizeof(mapname)); ExtraMaps_Add (mapname); } } } } } } } static void ExtraMaps_Clear (void) { FileList_Clear(&extralevels); } void ExtraMaps_NewGame (void) { ExtraMaps_Clear (); ExtraMaps_Init (); } /* ================== Host_Maps_f ================== */ void Host_Maps_f (void) { int i; filelist_item_t *level; for (level = extralevels, i = 0; level; level = level->next, i++) Con_SafePrintf (" %s\n", level->name); if (i) Con_SafePrintf ("%i map(s)\n", i); else Con_SafePrintf ("no maps found\n"); } //============================================================================== //johnfitz -- modlist management //============================================================================== filelist_item_t *modlist; void Modlist_Add (const char *name) { FileList_Add(name, &modlist); } #ifdef _WIN32 void Modlist_Init (void) { WIN32_FIND_DATA fdat, mod_fdat; HANDLE fhnd, mod_fhnd; char dir_string[MAX_OSPATH], mod_string[MAX_OSPATH]; q_snprintf (dir_string, sizeof(dir_string), "%s/*", com_basedir); fhnd = FindFirstFile(dir_string, &fdat); if (fhnd == INVALID_HANDLE_VALUE) return; do { if (!strcmp(fdat.cFileName, ".")) continue; q_snprintf (mod_string, sizeof(mod_string), "%s/%s/progs.dat", com_basedir, fdat.cFileName); mod_fhnd = FindFirstFile(mod_string, &mod_fdat); if (mod_fhnd != INVALID_HANDLE_VALUE) { FindClose(mod_fhnd); Modlist_Add(fdat.cFileName); } else { q_snprintf (mod_string, sizeof(mod_string), "%s/%s/*.pak", com_basedir, fdat.cFileName); mod_fhnd = FindFirstFile(mod_string, &mod_fdat); if (mod_fhnd != INVALID_HANDLE_VALUE) { FindClose(mod_fhnd); Modlist_Add(fdat.cFileName); } } } while (FindNextFile(fhnd, &fdat)); FindClose(fhnd); } #else void Modlist_Init (void) { DIR *dir_p, *mod_dir_p; struct dirent *dir_t, *mod_dir_t; char dir_string[MAX_OSPATH], mod_string[MAX_OSPATH]; q_snprintf (dir_string, sizeof(dir_string), "%s/", com_basedir); dir_p = opendir(dir_string); if (dir_p == NULL) return; while ((dir_t = readdir(dir_p)) != NULL) { if (!strcmp(dir_t->d_name, ".") || !strcmp(dir_t->d_name, "..")) continue; q_snprintf(mod_string, sizeof(mod_string), "%s%s/", dir_string, dir_t->d_name); mod_dir_p = opendir(mod_string); if (mod_dir_p == NULL) continue; // find progs.dat and pak file(s) while ((mod_dir_t = readdir(mod_dir_p)) != NULL) { if (!q_strcasecmp(mod_dir_t->d_name, "progs.dat")) { Modlist_Add(dir_t->d_name); break; } if (!q_strcasecmp(COM_FileGetExtension(mod_dir_t->d_name), "pak")) { Modlist_Add(dir_t->d_name); break; } } closedir(mod_dir_p); } closedir(dir_p); } #endif //============================================================================== //ericw -- demo list management //============================================================================== filelist_item_t *demolist; static void DemoList_Clear (void) { FileList_Clear (&demolist); } void DemoList_Rebuild (void) { DemoList_Clear (); DemoList_Init (); } // TODO: Factor out to a general-purpose file searching function void DemoList_Init (void) { #ifdef _WIN32 WIN32_FIND_DATA fdat; HANDLE fhnd; #else DIR *dir_p; struct dirent *dir_t; #endif char filestring[MAX_OSPATH]; char demname[32]; char ignorepakdir[32]; searchpath_t *search; pack_t *pak; int i; // we don't want to list the demos in id1 pakfiles, // because these are not "add-on" demos q_snprintf (ignorepakdir, sizeof(ignorepakdir), "/%s/", GAMENAME); for (search = com_searchpaths; search; search = search->next) { if (*search->filename) //directory { #ifdef _WIN32 q_snprintf (filestring, sizeof(filestring), "%s/*.dem", search->filename); fhnd = FindFirstFile(filestring, &fdat); if (fhnd == INVALID_HANDLE_VALUE) continue; do { COM_StripExtension(fdat.cFileName, demname, sizeof(demname)); FileList_Add (demname, &demolist); } while (FindNextFile(fhnd, &fdat)); FindClose(fhnd); #else q_snprintf (filestring, sizeof(filestring), "%s/", search->filename); dir_p = opendir(filestring); if (dir_p == NULL) continue; while ((dir_t = readdir(dir_p)) != NULL) { if (q_strcasecmp(COM_FileGetExtension(dir_t->d_name), "dem") != 0) continue; COM_StripExtension(dir_t->d_name, demname, sizeof(demname)); FileList_Add (demname, &demolist); } closedir(dir_p); #endif } else //pakfile { if (!strstr(search->pack->filename, ignorepakdir)) { //don't list standard id demos for (i = 0, pak = search->pack; i < pak->numfiles; i++) { if (!strcmp(COM_FileGetExtension(pak->files[i].name), "dem")) { COM_StripExtension(pak->files[i].name, demname, sizeof(demname)); FileList_Add (demname, &demolist); } } } } } } /* ================== Host_Mods_f -- johnfitz list all potential mod directories (contain either a pak file or a progs.dat) ================== */ void Host_Mods_f (void) { int i; filelist_item_t *mod; for (mod = modlist, i=0; mod; mod = mod->next, i++) Con_SafePrintf (" %s\n", mod->name); if (i) Con_SafePrintf ("%i mod(s)\n", i); else Con_SafePrintf ("no mods found\n"); } //============================================================================== /* ============= Host_Mapname_f -- johnfitz ============= */ void Host_Mapname_f (void) { if (sv.active) { Con_Printf ("\"mapname\" is \"%s\"\n", sv.name); return; } if (cls.state == ca_connected) { Con_Printf ("\"mapname\" is \"%s\"\n", cl.mapname); return; } Con_Printf ("no map loaded\n"); } /* ================== Host_Status_f ================== */ void Host_Status_f (void) { client_t *client; int seconds; int minutes; int hours = 0; int j; void (*print_fn) (const char *fmt, ...) __fp_attribute__((__format__(__printf__,1,2))); if (cmd_source == src_command) { if (!sv.active) { Cmd_ForwardToServer (); return; } print_fn = Con_Printf; } else print_fn = SV_ClientPrintf; print_fn ("host: %s\n", Cvar_VariableString ("hostname")); print_fn ("version: %4.2f\n", VERSION); if (tcpipAvailable) print_fn ("tcp/ip: %s\n", my_tcpip_address); if (ipxAvailable) print_fn ("ipx: %s\n", my_ipx_address); print_fn ("map: %s\n", sv.name); print_fn ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients); for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) { if (!client->active) continue; seconds = (int)(net_time - NET_QSocketGetTime(client->netconnection)); minutes = seconds / 60; if (minutes) { seconds -= (minutes * 60); hours = minutes / 60; if (hours) minutes -= (hours * 60); } else hours = 0; print_fn ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds); print_fn (" %s\n", NET_QSocketGetAddressString(client->netconnection)); } } /* ================== Host_God_f Sets client to godmode ================== */ void Host_God_f (void) { if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } if (pr_global_struct->deathmatch) return; //johnfitz -- allow user to explicitly set god mode to on or off switch (Cmd_Argc()) { case 1: sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE; if (!((int)sv_player->v.flags & FL_GODMODE) ) SV_ClientPrintf ("godmode OFF\n"); else SV_ClientPrintf ("godmode ON\n"); break; case 2: if (Q_atof(Cmd_Argv(1))) { sv_player->v.flags = (int)sv_player->v.flags | FL_GODMODE; SV_ClientPrintf ("godmode ON\n"); } else { sv_player->v.flags = (int)sv_player->v.flags & ~FL_GODMODE; SV_ClientPrintf ("godmode OFF\n"); } break; default: Con_Printf("god [value] : toggle god mode. values: 0 = off, 1 = on\n"); break; } //johnfitz } /* ================== Host_Notarget_f ================== */ void Host_Notarget_f (void) { if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } if (pr_global_struct->deathmatch) return; //johnfitz -- allow user to explicitly set notarget to on or off switch (Cmd_Argc()) { case 1: sv_player->v.flags = (int)sv_player->v.flags ^ FL_NOTARGET; if (!((int)sv_player->v.flags & FL_NOTARGET) ) SV_ClientPrintf ("notarget OFF\n"); else SV_ClientPrintf ("notarget ON\n"); break; case 2: if (Q_atof(Cmd_Argv(1))) { sv_player->v.flags = (int)sv_player->v.flags | FL_NOTARGET; SV_ClientPrintf ("notarget ON\n"); } else { sv_player->v.flags = (int)sv_player->v.flags & ~FL_NOTARGET; SV_ClientPrintf ("notarget OFF\n"); } break; default: Con_Printf("notarget [value] : toggle notarget mode. values: 0 = off, 1 = on\n"); break; } //johnfitz } qboolean noclip_anglehack; /* ================== Host_Noclip_f ================== */ void Host_Noclip_f (void) { if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } if (pr_global_struct->deathmatch) return; //johnfitz -- allow user to explicitly set noclip to on or off switch (Cmd_Argc()) { case 1: if (sv_player->v.movetype != MOVETYPE_NOCLIP) { noclip_anglehack = true; sv_player->v.movetype = MOVETYPE_NOCLIP; SV_ClientPrintf ("noclip ON\n"); } else { noclip_anglehack = false; sv_player->v.movetype = MOVETYPE_WALK; SV_ClientPrintf ("noclip OFF\n"); } break; case 2: if (Q_atof(Cmd_Argv(1))) { noclip_anglehack = true; sv_player->v.movetype = MOVETYPE_NOCLIP; SV_ClientPrintf ("noclip ON\n"); } else { noclip_anglehack = false; sv_player->v.movetype = MOVETYPE_WALK; SV_ClientPrintf ("noclip OFF\n"); } break; default: Con_Printf("noclip [value] : toggle noclip mode. values: 0 = off, 1 = on\n"); break; } //johnfitz } /* ================== Host_Fly_f Sets client to flymode ================== */ void Host_Fly_f (void) { if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } if (pr_global_struct->deathmatch) return; //johnfitz -- allow user to explicitly set noclip to on or off switch (Cmd_Argc()) { case 1: if (sv_player->v.movetype != MOVETYPE_FLY) { sv_player->v.movetype = MOVETYPE_FLY; SV_ClientPrintf ("flymode ON\n"); } else { sv_player->v.movetype = MOVETYPE_WALK; SV_ClientPrintf ("flymode OFF\n"); } break; case 2: if (Q_atof(Cmd_Argv(1))) { sv_player->v.movetype = MOVETYPE_FLY; SV_ClientPrintf ("flymode ON\n"); } else { sv_player->v.movetype = MOVETYPE_WALK; SV_ClientPrintf ("flymode OFF\n"); } break; default: Con_Printf("fly [value] : toggle fly mode. values: 0 = off, 1 = on\n"); break; } //johnfitz } /* ================== Host_Ping_f ================== */ void Host_Ping_f (void) { int i, j; float total; client_t *client; if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } SV_ClientPrintf ("Client ping times:\n"); for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) { if (!client->active) continue; total = 0; for (j = 0; j < NUM_PING_TIMES; j++) total+=client->ping_times[j]; total /= NUM_PING_TIMES; SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name); } } /* =============================================================================== SERVER TRANSITIONS =============================================================================== */ /* ====================== Host_Map_f handle a map <servername> command from the console. Active clients are kicked off. ====================== */ void Host_Map_f (void) { int i; char name[MAX_QPATH], *p; if (Cmd_Argc() < 2) //no map name given { if (cls.state == ca_dedicated) { if (sv.active) Con_Printf ("Current map: %s\n", sv.name); else Con_Printf ("Server not active\n"); } else if (cls.state == ca_connected) { Con_Printf ("Current map: %s ( %s )\n", cl.levelname, cl.mapname); } else { Con_Printf ("map <levelname>: start a new server\n"); } return; } if (cmd_source != src_command) return; cls.demonum = -1; // stop demo loop in case this fails CL_Disconnect (); Host_ShutdownServer(false); if (cls.state != ca_dedicated) IN_Activate(); key_dest = key_game; // remove console or menu SCR_BeginLoadingPlaque (); svs.serverflags = 0; // haven't completed an episode yet q_strlcpy (name, Cmd_Argv(1), sizeof(name)); // remove (any) trailing ".bsp" from mapname -- S.A. p = strstr(name, ".bsp"); if (p && p[4] == '\0') *p = '\0'; SV_SpawnServer (name); if (!sv.active) return; if (cls.state != ca_dedicated) { memset (cls.spawnparms, 0, MAX_MAPSTRING); for (i = 2; i < Cmd_Argc(); i++) { q_strlcat (cls.spawnparms, Cmd_Argv(i), MAX_MAPSTRING); q_strlcat (cls.spawnparms, " ", MAX_MAPSTRING); } Cmd_ExecuteString ("connect local", src_command); } } /* ================== Host_Changelevel_f Goes to a new map, taking all clients along ================== */ void Host_Changelevel_f (void) { char level[MAX_QPATH]; if (Cmd_Argc() != 2) { Con_Printf ("changelevel <levelname> : continue game on a new level\n"); return; } if (!sv.active || cls.demoplayback) { Con_Printf ("Only the server may changelevel\n"); return; } //johnfitz -- check for client having map before anything else q_snprintf (level, sizeof(level), "maps/%s.bsp", Cmd_Argv(1)); if (!COM_FileExists(level, NULL)) Host_Error ("cannot find map %s", level); //johnfitz if (cls.state != ca_dedicated) IN_Activate(); // -- S.A. key_dest = key_game; // remove console or menu SV_SaveSpawnparms (); q_strlcpy (level, Cmd_Argv(1), sizeof(level)); SV_SpawnServer (level); // also issue an error if spawn failed -- O.S. if (!sv.active) Host_Error ("cannot run map %s", level); } /* ================== Host_Restart_f Restarts the current server for a dead player ================== */ void Host_Restart_f (void) { char mapname[MAX_QPATH]; if (cls.demoplayback || !sv.active) return; if (cmd_source != src_command) return; q_strlcpy (mapname, sv.name, sizeof(mapname)); // mapname gets cleared in spawnserver SV_SpawnServer (mapname); if (!sv.active) Host_Error ("cannot restart map %s", mapname); } /* ================== Host_Reconnect_f This command causes the client to wait for the signon messages again. This is sent just before a server changes levels ================== */ void Host_Reconnect_f (void) { if (cls.demoplayback) // cross-map demo playback fix from Baker return; SCR_BeginLoadingPlaque (); cls.signon = 0; // need new connection messages } /* ===================== Host_Connect_f User command to connect to server ===================== */ void Host_Connect_f (void) { char name[MAX_QPATH]; cls.demonum = -1; // stop demo loop in case this fails if (cls.demoplayback) { CL_StopPlayback (); CL_Disconnect (); } q_strlcpy (name, Cmd_Argv(1), sizeof(name)); CL_EstablishConnection (name); Host_Reconnect_f (); } /* =============================================================================== LOAD / SAVE GAME =============================================================================== */ #define SAVEGAME_VERSION 5 /* =============== Host_SavegameComment Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current =============== */ void Host_SavegameComment (char *text) { int i; char kills[20]; for (i = 0; i < SAVEGAME_COMMENT_LENGTH; i++) text[i] = ' '; memcpy (text, cl.levelname, q_min(strlen(cl.levelname),22)); //johnfitz -- only copy 22 chars. sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); memcpy (text+22, kills, strlen(kills)); // convert space to _ to make stdio happy for (i = 0; i < SAVEGAME_COMMENT_LENGTH; i++) { if (text[i] == ' ') text[i] = '_'; } text[SAVEGAME_COMMENT_LENGTH] = '\0'; } /* =============== Host_Savegame_f =============== */ void Host_Savegame_f (void) { char name[MAX_OSPATH]; FILE *f; int i; char comment[SAVEGAME_COMMENT_LENGTH+1]; if (cmd_source != src_command) return; if (!sv.active) { Con_Printf ("Not playing a local game.\n"); return; } if (cl.intermission) { Con_Printf ("Can't save in intermission.\n"); return; } if (svs.maxclients != 1) { Con_Printf ("Can't save multiplayer games.\n"); return; } if (Cmd_Argc() != 2) { Con_Printf ("save <savename> : save a game\n"); return; } if (strstr(Cmd_Argv(1), "..")) { Con_Printf ("Relative pathnames are not allowed.\n"); return; } for (i=0 ; i<svs.maxclients ; i++) { if (svs.clients[i].active && (svs.clients[i].edict->v.health <= 0) ) { Con_Printf ("Can't savegame with a dead player\n"); return; } } q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1)); COM_AddExtension (name, ".sav", sizeof(name)); Con_Printf ("Saving game to %s...\n", name); f = fopen (name, "w"); if (!f) { Con_Printf ("ERROR: couldn't open.\n"); return; } fprintf (f, "%i\n", SAVEGAME_VERSION); Host_SavegameComment (comment); fprintf (f, "%s\n", comment); for (i = 0; i < NUM_SPAWN_PARMS; i++) fprintf (f, "%f\n", svs.clients->spawn_parms[i]); fprintf (f, "%d\n", current_skill); fprintf (f, "%s\n", sv.name); fprintf (f, "%f\n",sv.time); // write the light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { if (sv.lightstyles[i]) fprintf (f, "%s\n", sv.lightstyles[i]); else fprintf (f,"m\n"); } ED_WriteGlobals (f); for (i = 0; i < sv.num_edicts; i++) { ED_Write (f, EDICT_NUM(i)); fflush (f); } fclose (f); Con_Printf ("done.\n"); } /* =============== Host_Loadgame_f =============== */ void Host_Loadgame_f (void) { char name[MAX_OSPATH]; FILE *f; char mapname[MAX_QPATH]; float time, tfloat; char str[32768]; const char *start; int i, r; edict_t *ent; int entnum; int version; float spawn_parms[NUM_SPAWN_PARMS]; if (cmd_source != src_command) return; if (Cmd_Argc() != 2) { Con_Printf ("load <savename> : load a game\n"); return; } cls.demonum = -1; // stop demo loop in case this fails q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1)); COM_AddExtension (name, ".sav", sizeof(name)); // we can't call SCR_BeginLoadingPlaque, because too much stack space has // been used. The menu calls it before stuffing loadgame command // SCR_BeginLoadingPlaque (); Con_Printf ("Loading game from %s...\n", name); f = fopen (name, "r"); if (!f) { Con_Printf ("ERROR: couldn't open.\n"); return; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return; } fscanf (f, "%s\n", str); for (i = 0; i < NUM_SPAWN_PARMS; i++) fscanf (f, "%f\n", &spawn_parms[i]); // this silliness is so we can load 1.06 save files, which have float skill values fscanf (f, "%f\n", &tfloat); current_skill = (int)(tfloat + 0.1); Cvar_SetValue ("skill", (float)current_skill); fscanf (f, "%s\n",mapname); fscanf (f, "%f\n",&time); CL_Disconnect_f (); SV_SpawnServer (mapname); if (!sv.active) { fclose (f); Con_Printf ("Couldn't load map\n"); return; } sv.paused = true; // pause until all clients connect sv.loadgame = true; // load the light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { fscanf (f, "%s\n", str); sv.lightstyles[i] = (const char *)Hunk_Strdup (str, "lightstyles"); } // load the edicts out of the savegame file entnum = -1; // -1 is the globals while (!feof(f)) { qboolean inside_string = false; for (i = 0; i < (int) sizeof(str) - 1; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '"') { inside_string = !inside_string; } else if (r == '}' && !inside_string) // only handle } characters outside of quoted strings { i++; break; } } if (i == (int) sizeof(str) - 1) { fclose (f); Sys_Error ("Loadgame buffer overflow"); } str[i] = 0; start = str; start = COM_Parse(str); if (!com_token[0]) break; // end of file if (strcmp(com_token,"{")) { fclose (f); Sys_Error ("First token isn't a brace"); } if (entnum == -1) { // parse the global vars ED_ParseGlobals (start); } else { // parse an edict ent = EDICT_NUM(entnum); memset (&ent->v, 0, progs->entityfields * 4); ent->free = false; ED_ParseEdict (start, ent); // link it into the bsp tree if (!ent->free) SV_LinkEdict (ent, false); } entnum++; } sv.num_edicts = entnum; sv.time = time; fclose (f); for (i = 0; i < NUM_SPAWN_PARMS; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; if (cls.state != ca_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } } //============================================================================ /* ====================== Host_Name_f ====================== */ void Host_Name_f (void) { char newName[32]; if (Cmd_Argc () == 1) { Con_Printf ("\"name\" is \"%s\"\n", cl_name.string); return; } if (Cmd_Argc () == 2) q_strlcpy(newName, Cmd_Argv(1), sizeof(newName)); else q_strlcpy(newName, Cmd_Args(), sizeof(newName)); newName[15] = 0; // client_t structure actually says name[32]. if (cmd_source == src_command) { if (Q_strcmp(cl_name.string, newName) == 0) return; Cvar_Set ("_cl_name", newName); if (cls.state == ca_connected) Cmd_ForwardToServer (); return; } if (host_client->name[0] && strcmp(host_client->name, "unconnected") ) { if (Q_strcmp(host_client->name, newName) != 0) Con_Printf ("%s renamed to %s\n", host_client->name, newName); } Q_strcpy (host_client->name, newName); host_client->edict->v.netname = PR_SetEngineString(host_client->name); // send notification to all clients MSG_WriteByte (&sv.reliable_datagram, svc_updatename); MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); MSG_WriteString (&sv.reliable_datagram, host_client->name); } void Host_Say(qboolean teamonly) { int j; client_t *client; client_t *save; const char *p; char text[MAXCMDLINE], *p2; qboolean quoted; qboolean fromServer = false; if (cmd_source == src_command) { if (cls.state != ca_dedicated) { Cmd_ForwardToServer (); return; } fromServer = true; teamonly = false; } if (Cmd_Argc () < 2) return; save = host_client; p = Cmd_Args(); // remove quotes if present quoted = false; if (*p == '\"') { p++; quoted = true; } // turn on color set 1 if (!fromServer) q_snprintf (text, sizeof(text), "\001%s: %s", save->name, p); else q_snprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p); // check length & truncate if necessary j = (int) strlen(text); if (j >= (int) sizeof(text) - 1) { text[sizeof(text) - 2] = '\n'; text[sizeof(text) - 1] = '\0'; } else { p2 = text + j; while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)) ) { if (p2[-1] == '\"' && quoted) quoted = false; p2[-1] = '\0'; p2--; } p2[0] = '\n'; p2[1] = '\0'; } for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) { if (!client || !client->active || !client->spawned) continue; if (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team) continue; host_client = client; SV_ClientPrintf("%s", text); } host_client = save; if (cls.state == ca_dedicated) Sys_Printf("%s", &text[1]); } void Host_Say_f(void) { Host_Say(false); } void Host_Say_Team_f(void) { Host_Say(true); } void Host_Tell_f(void) { int j; client_t *client; client_t *save; const char *p; char text[MAXCMDLINE], *p2; qboolean quoted; if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } if (Cmd_Argc () < 3) return; p = Cmd_Args(); // remove quotes if present quoted = false; if (*p == '\"') { p++; quoted = true; } q_snprintf (text, sizeof(text), "%s: %s", host_client->name, p); // check length & truncate if necessary j = (int) strlen(text); if (j >= (int) sizeof(text) - 1) { text[sizeof(text) - 2] = '\n'; text[sizeof(text) - 1] = '\0'; } else { p2 = text + j; while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)) ) { if (p2[-1] == '\"' && quoted) quoted = false; p2[-1] = '\0'; p2--; } p2[0] = '\n'; p2[1] = '\0'; } save = host_client; for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) { if (!client->active || !client->spawned) continue; if (q_strcasecmp(client->name, Cmd_Argv(1))) continue; host_client = client; SV_ClientPrintf("%s", text); break; } host_client = save; } /* ================== Host_Color_f ================== */ void Host_Color_f(void) { int top, bottom; int playercolor; if (Cmd_Argc() == 1) { Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f); Con_Printf ("color <0-13> [0-13]\n"); return; } if (Cmd_Argc() == 2) top = bottom = atoi(Cmd_Argv(1)); else { top = atoi(Cmd_Argv(1)); bottom = atoi(Cmd_Argv(2)); } top &= 15; if (top > 13) top = 13; bottom &= 15; if (bottom > 13) bottom = 13; playercolor = top*16 + bottom; if (cmd_source == src_command) { Cvar_SetValue ("_cl_color", playercolor); if (cls.state == ca_connected) Cmd_ForwardToServer (); return; } host_client->colors = playercolor; host_client->edict->v.team = bottom + 1; // send notification to all clients MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); MSG_WriteByte (&sv.reliable_datagram, host_client->colors); } /* ================== Host_Kill_f ================== */ void Host_Kill_f (void) { if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } if (sv_player->v.health <= 0) { SV_ClientPrintf ("Can't suicide -- allready dead!\n"); return; } pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(sv_player); PR_ExecuteProgram (pr_global_struct->ClientKill); } /* ================== Host_Pause_f ================== */ void Host_Pause_f (void) { //ericw -- demo pause support (inspired by MarkV) if (cls.demoplayback) { cls.demopaused = !cls.demopaused; cl.paused = cls.demopaused; return; } if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } if (!pausable.value) SV_ClientPrintf ("Pause not allowed.\n"); else { sv.paused ^= 1; if (sv.paused) { SV_BroadcastPrintf ("%s paused the game\n", PR_GetString(sv_player->v.netname)); } else { SV_BroadcastPrintf ("%s unpaused the game\n",PR_GetString(sv_player->v.netname)); } // send notification to all clients MSG_WriteByte (&sv.reliable_datagram, svc_setpause); MSG_WriteByte (&sv.reliable_datagram, sv.paused); } } //=========================================================================== /* ================== Host_PreSpawn_f ================== */ void Host_PreSpawn_f (void) { if (cmd_source == src_command) { Con_Printf ("prespawn is not valid from the console\n"); return; } if (host_client->spawned) { Con_Printf ("prespawn not valid -- allready spawned\n"); return; } SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize); MSG_WriteByte (&host_client->message, svc_signonnum); MSG_WriteByte (&host_client->message, 2); host_client->sendsignon = true; } /* ================== Host_Spawn_f ================== */ void Host_Spawn_f (void) { int i; client_t *client; edict_t *ent; if (cmd_source == src_command) { Con_Printf ("spawn is not valid from the console\n"); return; } if (host_client->spawned) { Con_Printf ("Spawn not valid -- allready spawned\n"); return; } // run the entrance script if (sv.loadgame) { // loaded games are fully inited allready // if this is the last client to be connected, unpause sv.paused = false; } else { // set up the edict ent = host_client->edict; memset (&ent->v, 0, progs->entityfields * 4); ent->v.colormap = NUM_FOR_EDICT(ent); ent->v.team = (host_client->colors & 15) + 1; ent->v.netname = PR_SetEngineString(host_client->name); // copy spawn parms out of the client_t for (i=0 ; i< NUM_SPAWN_PARMS ; i++) (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; // call the spawn function pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(sv_player); PR_ExecuteProgram (pr_global_struct->ClientConnect); if ((Sys_DoubleTime() - NET_QSocketGetTime(host_client->netconnection)) <= sv.time) Sys_Printf ("%s entered the game\n", host_client->name); PR_ExecuteProgram (pr_global_struct->PutClientInServer); } // send all current names, colors, and frag counts SZ_Clear (&host_client->message); // send time of update MSG_WriteByte (&host_client->message, svc_time); MSG_WriteFloat (&host_client->message, sv.time); for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) { MSG_WriteByte (&host_client->message, svc_updatename); MSG_WriteByte (&host_client->message, i); MSG_WriteString (&host_client->message, client->name); MSG_WriteByte (&host_client->message, svc_updatefrags); MSG_WriteByte (&host_client->message, i); MSG_WriteShort (&host_client->message, client->old_frags); MSG_WriteByte (&host_client->message, svc_updatecolors); MSG_WriteByte (&host_client->message, i); MSG_WriteByte (&host_client->message, client->colors); } // send all current light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { MSG_WriteByte (&host_client->message, svc_lightstyle); MSG_WriteByte (&host_client->message, (char)i); MSG_WriteString (&host_client->message, sv.lightstyles[i]); } // // send some stats // MSG_WriteByte (&host_client->message, svc_updatestat); MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS); MSG_WriteLong (&host_client->message, pr_global_struct->total_secrets); MSG_WriteByte (&host_client->message, svc_updatestat); MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS); MSG_WriteLong (&host_client->message, pr_global_struct->total_monsters); MSG_WriteByte (&host_client->message, svc_updatestat); MSG_WriteByte (&host_client->message, STAT_SECRETS); MSG_WriteLong (&host_client->message, pr_global_struct->found_secrets); MSG_WriteByte (&host_client->message, svc_updatestat); MSG_WriteByte (&host_client->message, STAT_MONSTERS); MSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters); // // send a fixangle // Never send a roll angle, because savegames can catch the server // in a state where it is expecting the client to correct the angle // and it won't happen if the game was just loaded, so you wind up // with a permanent head tilt ent = EDICT_NUM( 1 + (host_client - svs.clients) ); MSG_WriteByte (&host_client->message, svc_setangle); for (i = 0; i < 2; i++) MSG_WriteAngle (&host_client->message, ent->v.angles[i] ); MSG_WriteAngle (&host_client->message, 0 ); SV_WriteClientdataToMessage (sv_player, &host_client->message); MSG_WriteByte (&host_client->message, svc_signonnum); MSG_WriteByte (&host_client->message, 3); host_client->sendsignon = true; } /* ================== Host_Begin_f ================== */ void Host_Begin_f (void) { if (cmd_source == src_command) { Con_Printf ("begin is not valid from the console\n"); return; } host_client->spawned = true; } //=========================================================================== /* ================== Host_Kick_f Kicks a user off of the server ================== */ void Host_Kick_f (void) { const char *who; const char *message = NULL; client_t *save; int i; qboolean byNumber = false; if (cmd_source == src_command) { if (!sv.active) { Cmd_ForwardToServer (); return; } } else if (pr_global_struct->deathmatch) return; save = host_client; if (Cmd_Argc() > 2 && Q_strcmp(Cmd_Argv(1), "#") == 0) { i = Q_atof(Cmd_Argv(2)) - 1; if (i < 0 || i >= svs.maxclients) return; if (!svs.clients[i].active) return; host_client = &svs.clients[i]; byNumber = true; } else { for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) { if (!host_client->active) continue; if (q_strcasecmp(host_client->name, Cmd_Argv(1)) == 0) break; } } if (i < svs.maxclients) { if (cmd_source == src_command) if (cls.state == ca_dedicated) who = "Console"; else who = cl_name.string; else who = save->name; // can't kick yourself! if (host_client == save) return; if (Cmd_Argc() > 2) { message = COM_Parse(Cmd_Args()); if (byNumber) { message++; // skip the # while (*message == ' ') // skip white space message++; message += strlen(Cmd_Argv(2)); // skip the number } while (*message && *message == ' ') message++; } if (message) SV_ClientPrintf ("Kicked by %s: %s\n", who, message); else SV_ClientPrintf ("Kicked by %s\n", who); SV_DropClient (false); } host_client = save; } /* =============================================================================== DEBUGGING TOOLS =============================================================================== */ /* ================== Host_Give_f ================== */ void Host_Give_f (void) { const char *t; int v; eval_t *val; if (cmd_source == src_command) { Cmd_ForwardToServer (); return; } if (pr_global_struct->deathmatch) return; t = Cmd_Argv(1); v = atoi (Cmd_Argv(2)); switch (t[0]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // MED 01/04/97 added hipnotic give stuff if (hipnotic) { if (t[0] == '6') { if (t[1] == 'a') sv_player->v.items = (int)sv_player->v.items | HIT_PROXIMITY_GUN; else sv_player->v.items = (int)sv_player->v.items | IT_GRENADE_LAUNCHER; } else if (t[0] == '9') sv_player->v.items = (int)sv_player->v.items | HIT_LASER_CANNON; else if (t[0] == '0') sv_player->v.items = (int)sv_player->v.items | HIT_MJOLNIR; else if (t[0] >= '2') sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2')); } else { if (t[0] >= '2') sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2')); } break; case 's': if (rogue) { val = GetEdictFieldValue(sv_player, "ammo_shells1"); if (val) val->_float = v; } sv_player->v.ammo_shells = v; break; case 'n': if (rogue) { val = GetEdictFieldValue(sv_player, "ammo_nails1"); if (val) { val->_float = v; if (sv_player->v.weapon <= IT_LIGHTNING) sv_player->v.ammo_nails = v; } } else { sv_player->v.ammo_nails = v; } break; case 'l': if (rogue) { val = GetEdictFieldValue(sv_player, "ammo_lava_nails"); if (val) { val->_float = v; if (sv_player->v.weapon > IT_LIGHTNING) sv_player->v.ammo_nails = v; } } break; case 'r': if (rogue) { val = GetEdictFieldValue(sv_player, "ammo_rockets1"); if (val) { val->_float = v; if (sv_player->v.weapon <= IT_LIGHTNING) sv_player->v.ammo_rockets = v; } } else { sv_player->v.ammo_rockets = v; } break; case 'm': if (rogue) { val = GetEdictFieldValue(sv_player, "ammo_multi_rockets"); if (val) { val->_float = v; if (sv_player->v.weapon > IT_LIGHTNING) sv_player->v.ammo_rockets = v; } } break; case 'h': sv_player->v.health = v; break; case 'c': if (rogue) { val = GetEdictFieldValue(sv_player, "ammo_cells1"); if (val) { val->_float = v; if (sv_player->v.weapon <= IT_LIGHTNING) sv_player->v.ammo_cells = v; } } else { sv_player->v.ammo_cells = v; } break; case 'p': if (rogue) { val = GetEdictFieldValue(sv_player, "ammo_plasma"); if (val) { val->_float = v; if (sv_player->v.weapon > IT_LIGHTNING) sv_player->v.ammo_cells = v; } } break; //johnfitz -- give armour case 'a': if (v > 150) { sv_player->v.armortype = 0.8; sv_player->v.armorvalue = v; sv_player->v.items = sv_player->v.items - ((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR3; } else if (v > 100) { sv_player->v.armortype = 0.6; sv_player->v.armorvalue = v; sv_player->v.items = sv_player->v.items - ((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR2; } else if (v >= 0) { sv_player->v.armortype = 0.3; sv_player->v.armorvalue = v; sv_player->v.items = sv_player->v.items - ((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR1; } break; //johnfitz } //johnfitz -- update currentammo to match new ammo (so statusbar updates correctly) switch ((int)(sv_player->v.weapon)) { case IT_SHOTGUN: case IT_SUPER_SHOTGUN: sv_player->v.currentammo = sv_player->v.ammo_shells; break; case IT_NAILGUN: case IT_SUPER_NAILGUN: case RIT_LAVA_SUPER_NAILGUN: sv_player->v.currentammo = sv_player->v.ammo_nails; break; case IT_GRENADE_LAUNCHER: case IT_ROCKET_LAUNCHER: case RIT_MULTI_GRENADE: case RIT_MULTI_ROCKET: sv_player->v.currentammo = sv_player->v.ammo_rockets; break; case IT_LIGHTNING: case HIT_LASER_CANNON: case HIT_MJOLNIR: sv_player->v.currentammo = sv_player->v.ammo_cells; break; case RIT_LAVA_NAILGUN: //same as IT_AXE if (rogue) sv_player->v.currentammo = sv_player->v.ammo_nails; break; case RIT_PLASMA_GUN: //same as HIT_PROXIMITY_GUN if (rogue) sv_player->v.currentammo = sv_player->v.ammo_cells; if (hipnotic) sv_player->v.currentammo = sv_player->v.ammo_rockets; break; } //johnfitz } edict_t *FindViewthing (void) { int i; edict_t *e; for (i=0 ; i<sv.num_edicts ; i++) { e = EDICT_NUM(i); if ( !strcmp (PR_GetString(e->v.classname), "viewthing") ) return e; } Con_Printf ("No viewthing on map\n"); return NULL; } /* ================== Host_Viewmodel_f ================== */ void Host_Viewmodel_f (void) { edict_t *e; qmodel_t *m; e = FindViewthing (); if (!e) return; m = Mod_ForName (Cmd_Argv(1), false); if (!m) { Con_Printf ("Can't load %s\n", Cmd_Argv(1)); return; } e->v.frame = 0; cl.model_precache[(int)e->v.modelindex] = m; } /* ================== Host_Viewframe_f ================== */ void Host_Viewframe_f (void) { edict_t *e; int f; qmodel_t *m; e = FindViewthing (); if (!e) return; m = cl.model_precache[(int)e->v.modelindex]; f = atoi(Cmd_Argv(1)); if (f >= m->numframes) f = m->numframes - 1; e->v.frame = f; } void PrintFrameName (qmodel_t *m, int frame) { aliashdr_t *hdr; maliasframedesc_t *pframedesc; hdr = (aliashdr_t *)Mod_Extradata (m); if (!hdr) return; pframedesc = &hdr->frames[frame]; Con_Printf ("frame %i: %s\n", frame, pframedesc->name); } /* ================== Host_Viewnext_f ================== */ void Host_Viewnext_f (void) { edict_t *e; qmodel_t *m; e = FindViewthing (); if (!e) return; m = cl.model_precache[(int)e->v.modelindex]; e->v.frame = e->v.frame + 1; if (e->v.frame >= m->numframes) e->v.frame = m->numframes - 1; PrintFrameName (m, e->v.frame); } /* ================== Host_Viewprev_f ================== */ void Host_Viewprev_f (void) { edict_t *e; qmodel_t *m; e = FindViewthing (); if (!e) return; m = cl.model_precache[(int)e->v.modelindex]; e->v.frame = e->v.frame - 1; if (e->v.frame < 0) e->v.frame = 0; PrintFrameName (m, e->v.frame); } /* =============================================================================== DEMO LOOP CONTROL =============================================================================== */ /* ================== Host_Startdemos_f ================== */ void Host_Startdemos_f (void) { int i, c; if (cls.state == ca_dedicated) return; c = Cmd_Argc() - 1; if (c > MAX_DEMOS) { Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS); c = MAX_DEMOS; } Con_Printf ("%i demo(s) in loop\n", c); for (i = 1; i < c + 1; i++) q_strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof(cls.demos[0])); if (!sv.active && cls.demonum != -1 && !cls.demoplayback) { cls.demonum = 0; if (!fitzmode) { /* QuakeSpasm customization: */ /* go straight to menu, no CL_NextDemo */ cls.demonum = -1; Cbuf_InsertText("menu_main\n"); return; } CL_NextDemo (); } else { cls.demonum = -1; } } /* ================== Host_Demos_f Return to looping demos ================== */ void Host_Demos_f (void) { if (cls.state == ca_dedicated) return; if (cls.demonum == -1) cls.demonum = 1; CL_Disconnect_f (); CL_NextDemo (); } /* ================== Host_Stopdemo_f Return to looping demos ================== */ void Host_Stopdemo_f (void) { if (cls.state == ca_dedicated) return; if (!cls.demoplayback) return; CL_StopPlayback (); CL_Disconnect (); } //============================================================================= /* ================== Host_InitCommands ================== */ void Host_InitCommands (void) { Cmd_AddCommand ("maps", Host_Maps_f); //johnfitz Cmd_AddCommand ("mods", Host_Mods_f); //johnfitz Cmd_AddCommand ("games", Host_Mods_f); // as an alias to "mods" -- S.A. / QuakeSpasm Cmd_AddCommand ("mapname", Host_Mapname_f); //johnfitz Cmd_AddCommand ("status", Host_Status_f); Cmd_AddCommand ("quit", Host_Quit_f); Cmd_AddCommand ("god", Host_God_f); Cmd_AddCommand ("notarget", Host_Notarget_f); Cmd_AddCommand ("fly", Host_Fly_f); Cmd_AddCommand ("map", Host_Map_f); Cmd_AddCommand ("restart", Host_Restart_f); Cmd_AddCommand ("changelevel", Host_Changelevel_f); Cmd_AddCommand ("connect", Host_Connect_f); Cmd_AddCommand ("reconnect", Host_Reconnect_f); Cmd_AddCommand ("name", Host_Name_f); Cmd_AddCommand ("noclip", Host_Noclip_f); Cmd_AddCommand ("say", Host_Say_f); Cmd_AddCommand ("say_team", Host_Say_Team_f); Cmd_AddCommand ("tell", Host_Tell_f); Cmd_AddCommand ("color", Host_Color_f); Cmd_AddCommand ("kill", Host_Kill_f); Cmd_AddCommand ("pause", Host_Pause_f); Cmd_AddCommand ("spawn", Host_Spawn_f); Cmd_AddCommand ("begin", Host_Begin_f); Cmd_AddCommand ("prespawn", Host_PreSpawn_f); Cmd_AddCommand ("kick", Host_Kick_f); Cmd_AddCommand ("ping", Host_Ping_f); Cmd_AddCommand ("load", Host_Loadgame_f); Cmd_AddCommand ("save", Host_Savegame_f); Cmd_AddCommand ("give", Host_Give_f); Cmd_AddCommand ("startdemos", Host_Startdemos_f); Cmd_AddCommand ("demos", Host_Demos_f); Cmd_AddCommand ("stopdemo", Host_Stopdemo_f); Cmd_AddCommand ("viewmodel", Host_Viewmodel_f); Cmd_AddCommand ("viewframe", Host_Viewframe_f); Cmd_AddCommand ("viewnext", Host_Viewnext_f); Cmd_AddCommand ("viewprev", Host_Viewprev_f); Cmd_AddCommand ("mcache", Mod_Print); } �������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_defs.h������������������������������������������������������������������0000644�0000000�0000000�00000015401�12407762022�015462� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * net_defs.h -- functions and data private to the network layer * net_sys.h and its dependencies must be included before net_defs.h. * * Copyright (C) 1996-1997 Id Software, Inc. * Copyright (C) 2005-2012 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #ifndef __NET_DEFS_H #define __NET_DEFS_H struct qsockaddr { #if defined(HAVE_SA_LEN) unsigned char qsa_len; unsigned char qsa_family; #else short qsa_family; #endif /* BSD, sockaddr */ unsigned char qsa_data[14]; }; #define NET_HEADERSIZE (2 * sizeof(unsigned int)) #define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE) // NetHeader flags #define NETFLAG_LENGTH_MASK 0x0000ffff #define NETFLAG_DATA 0x00010000 #define NETFLAG_ACK 0x00020000 #define NETFLAG_NAK 0x00040000 #define NETFLAG_EOM 0x00080000 #define NETFLAG_UNRELIABLE 0x00100000 #define NETFLAG_CTL 0x80000000 #define NET_PROTOCOL_VERSION 3 /** This is the network info/connection protocol. It is used to find Quake servers, get info about them, and connect to them. Once connected, the Quake game protocol (documented elsewhere) is used. General notes: game_name is currently always "QUAKE", but is there so this same protocol can be used for future games as well; can you say Quake2? CCREQ_CONNECT string game_name "QUAKE" byte net_protocol_version NET_PROTOCOL_VERSION CCREQ_SERVER_INFO string game_name "QUAKE" byte net_protocol_version NET_PROTOCOL_VERSION CCREQ_PLAYER_INFO byte player_number CCREQ_RULE_INFO string rule CCREP_ACCEPT long port CCREP_REJECT string reason CCREP_SERVER_INFO string server_address string host_name string level_name byte current_players byte max_players byte protocol_version NET_PROTOCOL_VERSION CCREP_PLAYER_INFO byte player_number string name long colors long frags long connect_time string address CCREP_RULE_INFO string rule string value note: There are two address forms used above. The short form is just a port number. The address that goes along with the port is defined as "whatever address you receive this reponse from". This lets us use the host OS to solve the problem of multiple host addresses (possibly with no routing between them); the host will use the right address when we reply to the inbound connection request. The long from is a full address and port in a string. It is used for returning the address of a server that is not running locally. **/ #define CCREQ_CONNECT 0x01 #define CCREQ_SERVER_INFO 0x02 #define CCREQ_PLAYER_INFO 0x03 #define CCREQ_RULE_INFO 0x04 #define CCREP_ACCEPT 0x81 #define CCREP_REJECT 0x82 #define CCREP_SERVER_INFO 0x83 #define CCREP_PLAYER_INFO 0x84 #define CCREP_RULE_INFO 0x85 typedef struct qsocket_s { struct qsocket_s *next; double connecttime; double lastMessageTime; double lastSendTime; qboolean disconnected; qboolean canSend; qboolean sendNext; int driver; int landriver; sys_socket_t socket; void *driverdata; unsigned int ackSequence; unsigned int sendSequence; unsigned int unreliableSendSequence; int sendMessageLength; byte sendMessage [NET_MAXMESSAGE]; unsigned int receiveSequence; unsigned int unreliableReceiveSequence; int receiveMessageLength; byte receiveMessage [NET_MAXMESSAGE]; struct qsockaddr addr; char address[NET_NAMELEN]; } qsocket_t; extern qsocket_t *net_activeSockets; extern qsocket_t *net_freeSockets; extern int net_numsockets; typedef struct { const char *name; qboolean initialized; sys_socket_t controlSock; sys_socket_t (*Init) (void); void (*Shutdown) (void); void (*Listen) (qboolean state); sys_socket_t (*Open_Socket) (int port); int (*Close_Socket) (sys_socket_t socketid); int (*Connect) (sys_socket_t socketid, struct qsockaddr *addr); sys_socket_t (*CheckNewConnections) (void); int (*Read) (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr); int (*Write) (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr); int (*Broadcast) (sys_socket_t socketid, byte *buf, int len); const char * (*AddrToString) (struct qsockaddr *addr); int (*StringToAddr) (const char *string, struct qsockaddr *addr); int (*GetSocketAddr) (sys_socket_t socketid, struct qsockaddr *addr); int (*GetNameFromAddr) (struct qsockaddr *addr, char *name); int (*GetAddrFromName) (const char *name, struct qsockaddr *addr); int (*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2); int (*GetSocketPort) (struct qsockaddr *addr); int (*SetSocketPort) (struct qsockaddr *addr, int port); } net_landriver_t; #define MAX_NET_DRIVERS 8 extern net_landriver_t net_landrivers[]; extern const int net_numlandrivers; typedef struct { const char *name; qboolean initialized; int (*Init) (void); void (*Listen) (qboolean state); void (*SearchForHosts) (qboolean xmit); qsocket_t *(*Connect) (const char *host); qsocket_t *(*CheckNewConnections) (void); int (*QGetMessage) (qsocket_t *sock); int (*QSendMessage) (qsocket_t *sock, sizebuf_t *data); int (*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data); qboolean (*CanSendMessage) (qsocket_t *sock); qboolean (*CanSendUnreliableMessage) (qsocket_t *sock); void (*Close) (qsocket_t *sock); void (*Shutdown) (void); } net_driver_t; extern net_driver_t net_drivers[]; extern const int net_numdrivers; /* Loop driver must always be registered the first */ #define IS_LOOP_DRIVER(p) ((p) == 0) extern int net_driverlevel; extern int messagesSent; extern int messagesReceived; extern int unreliableMessagesSent; extern int unreliableMessagesReceived; qsocket_t *NET_NewQSocket (void); void NET_FreeQSocket(qsocket_t *); double SetNetTime(void); #define HOSTCACHESIZE 8 typedef struct { char name[16]; char map[16]; char cname[32]; int users; int maxusers; int driver; int ldriver; struct qsockaddr addr; } hostcache_t; extern int hostCacheCount; extern hostcache_t hostcache[HOSTCACHESIZE]; typedef struct _PollProcedure { struct _PollProcedure *next; double nextTime; void (*procedure)(void *); void *arg; } PollProcedure; void SchedulePollProcedure(PollProcedure *pp, double timeOffset); #endif /* __NET_DEFS_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/resource.h������������������������������������������������������������������0000644�0000000�0000000�00000001274�11340073704�015522� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _QUAKE_RESOURCE_H #define _QUAKE_RESOURCE_H //{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by winquake.rc // #define IDS_STRING1 1 #define IDI_ICON2 1 #define IDD_DIALOG1 108 #define IDD_PROGRESS 109 #define IDC_PROGRESS 1000 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 113 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1004 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif #endif /* _QUAKE_RESOURCE_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/Makefile.w64����������������������������������������������������������������0000644�0000000�0000000�00000013631�12513254455�015610� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# GNU Makefile for compiling Win64 quakespasm.exe using MinGW-w64. # Usage: "make -f Makefile.w64" # To cross-compile on Linux hosts, see the "build_cross_win32*.sh" scripts. # "make DEBUG=1" to build a debug client. # "make SDL_CONFIG=/path/to/sdl-config" to override the locally included SDL versions. # "make WINSOCK2=0" to use the old WinSock 1.1 api (NOT RECOMMENDED) ### Enable/disable SDL2 USE_SDL2=0 ### Enable/disable codecs for streaming music support USE_CODEC_WAVE=1 USE_CODEC_FLAC=1 USE_CODEC_MP3=1 USE_CODEC_VORBIS=1 USE_CODEC_OPUS=1 # either mikmod (preferred) or modplug, not both USE_CODEC_MIKMOD=1 USE_CODEC_MODPLUG=0 USE_CODEC_UMX=1 # which library to use for mp3 decoding: mad or mpg123 MP3LIB=mad # which library to use for ogg decoding: vorbis or tremor VORBISLIB=vorbis # --------------------------- # Helper functions # --------------------------- check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi;) # --------------------------- DEBUG ?= 0 WINSOCK2?= 1 # --------------------------- # build variables # --------------------------- CC = gcc LINKER = $(CC) WINDRES = windres STRIP = strip CPUFLAGS= LDFLAGS = DFLAGS ?= CFLAGS ?= -Wall -Wno-trigraphs CFLAGS += $(CPUFLAGS) ifneq ($(DEBUG),0) DFLAGS += -DDEBUG CFLAGS += -g do_strip= else DFLAGS += -DNDEBUG CFLAGS += -O2 CFLAGS += $(call check_gcc,-fweb,) CFLAGS += $(call check_gcc,-frename-registers,) cmd_strip=$(STRIP) $(1) define do_strip $(call cmd_strip,$(1)); endef endif ifeq ($(USE_SDL2),1) CFLAGS += -DUSE_SDL2 endif # default to our local SDL[2] for build ifeq ($(USE_SDL2),1) SDL_CONFIG ?=../Windows/SDL2/bin/sdl2-config --prefix=../Windows/SDL2 --lib-suffix=64 else SDL_CONFIG ?=../Windows/SDL/bin/sdl-config --prefix=../Windows/SDL --lib-suffix=64 endif SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags) SDL_LIBS := $(shell $(SDL_CONFIG) --libs) ifeq ($(WINSOCK2),1) DEFWINSOCK :=-D_USE_WINSOCK2 LIBWINSOCK := -lws2_32 else DEFWINSOCK := LIBWINSOCK := -lwsock32 endif CFLAGS += $(DEFWINSOCK) NET_LIBS := $(LIBWINSOCK) ifneq ($(VORBISLIB),vorbis) ifneq ($(VORBISLIB),tremor) $(error Invalid VORBISLIB setting) endif endif ifneq ($(MP3LIB),mpg123) ifneq ($(MP3LIB),mad) $(error Invalid MP3LIB setting) endif endif ifeq ($(MP3LIB),mad) mp3_obj=snd_mp3.o lib_mp3dec=-lmad endif ifeq ($(MP3LIB),mpg123) mp3_obj=snd_mpg123.o lib_mp3dec=-lmpg123 endif ifeq ($(VORBISLIB),vorbis) cpp_vorbisdec= lib_vorbisdec=-lvorbisfile -lvorbis -logg endif ifeq ($(VORBISLIB),tremor) cpp_vorbisdec=-DVORBIS_USE_TREMOR lib_vorbisdec=-lvorbisidec -logg endif CODECLIBS := ifeq ($(USE_CODEC_WAVE),1) CFLAGS+= -DUSE_CODEC_WAVE endif ifeq ($(USE_CODEC_FLAC),1) CFLAGS+= -DUSE_CODEC_FLAC CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x64 CODECLIBS+= -lFLAC endif ifeq ($(USE_CODEC_OPUS),1) CFLAGS+= -DUSE_CODEC_OPUS CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x64 CODECLIBS+= -lopusfile -lopus -logg endif ifeq ($(USE_CODEC_VORBIS),1) CFLAGS+= -DUSE_CODEC_VORBIS $(cpp_vorbisdec) CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x64 CODECLIBS+= $(lib_vorbisdec) endif ifeq ($(USE_CODEC_MP3),1) CFLAGS+= -DUSE_CODEC_MP3 CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x64 CODECLIBS+= $(lib_mp3dec) endif ifeq ($(USE_CODEC_MIKMOD),1) CFLAGS+= -DUSE_CODEC_MIKMOD CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x64 CODECLIBS+= -lmikmod endif ifeq ($(USE_CODEC_MODPLUG),1) CFLAGS+= -DUSE_CODEC_MODPLUG CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x64 CODECLIBS+= -lmodplug endif ifeq ($(USE_CODEC_UMX),1) CFLAGS+= -DUSE_CODEC_UMX endif CFLAGS+= $(CODEC_INC) COMMON_LIBS:= -lm -lopengl32 -lwinmm LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS) # --------------------------- # targets # --------------------------- .PHONY: clean debug release DEFAULT_TARGET := quakespasm.exe # --------------------------- # rules # --------------------------- %.o: %.c $(CC) $(DFLAGS) -c $(CFLAGS) $(SDL_CFLAGS) -o $@ $^ %.res: ../Windows/%.rc $(WINDRES) --output-format=coff -I../Windows -o $@ $^ # ---------------------------------------------------------------------------- # objects # ---------------------------------------------------------------------------- MUSIC_OBJS:= bgmusic.o \ snd_codec.o \ snd_flac.o \ snd_wave.o \ snd_vorbis.o \ snd_opus.o \ $(mp3_obj) \ snd_mikmod.o \ snd_modplug.o \ snd_umx.o COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS) SYSOBJ_SND := snd_sdl.o SYSOBJ_CDA := cd_sdl.o SYSOBJ_INPUT := in_sdl.o SYSOBJ_GL_VID:= gl_vidsdl.o SYSOBJ_NET := net_win.o net_wins.o net_wipx.o SYSOBJ_SYS := pl_win.o sys_sdl_win.o SYSOBJ_MAIN:= main_sdl.o SYSOBJ_RES := QuakeSpasm.res GLOBJS = \ gl_refrag.o \ gl_rlight.o \ gl_rmain.o \ gl_fog.o \ gl_rmisc.o \ r_part.o \ r_world.o \ gl_screen.o \ gl_sky.o \ gl_warp.o \ $(SYSOBJ_GL_VID) \ gl_draw.o \ image.o \ gl_texmgr.o \ gl_mesh.o \ r_sprite.o \ r_alias.o \ r_brush.o \ gl_model.o OBJS := strlcat.o \ strlcpy.o \ $(GLOBJS) \ $(SYSOBJ_INPUT) \ $(COMOBJ_SND) \ $(SYSOBJ_SND) \ $(SYSOBJ_CDA) \ $(SYSOBJ_NET) \ net_dgrm.o \ net_loop.o \ net_main.o \ chase.o \ cl_demo.o \ cl_input.o \ cl_main.o \ cl_parse.o \ cl_tent.o \ console.o \ keys.o \ menu.o \ sbar.o \ view.o \ wad.o \ cmd.o \ common.o \ crc.o \ cvar.o \ cfgfile.o \ host.o \ host_cmd.o \ mathlib.o \ pr_cmds.o \ pr_edict.o \ pr_exec.o \ sv_main.o \ sv_move.o \ sv_phys.o \ sv_user.o \ world.o \ zone.o \ $(SYSOBJ_SYS) $(SYSOBJ_MAIN) $(SYSOBJ_RES) # ------------------------ # MinGW-w64 build rules # ------------------------ quakespasm.exe: $(OBJS) $(LINKER) $(OBJS) $(LDFLAGS) $(LIBS) $(SDL_LIBS) -o $@ $(call do_strip,$@) release: quakespasm.exe debug: $(error Use "make DEBUG=1") clean: rm -f $(shell find . \( -name '*~' -o -name '#*#' -o -name '*.o' -o -name '*.res' -o -name $(DEFAULT_TARGET) \) -print) �������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/build_cross_win32.sh��������������������������������������������������������0000755�0000000�0000000�00000000755�12475156650�017432� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # Change this script to meet your needs and/or environment. #TARGET=i686-w64-mingw32 TARGET=i686-pc-mingw32 #PREFIX=/opt/cross_win32 PREFIX=/usr/local/cross-win32 PATH="$PREFIX/bin:$PATH" export PATH MAKE_CMD=make CC="$TARGET-gcc" AS="$TARGET-as" RANLIB="$TARGET-ranlib" AR="$TARGET-ar" WINDRES="$TARGET-windres" STRIP="$TARGET-strip" export PATH CC AS AR RANLIB WINDRES STRIP exec $MAKE_CMD CC=$CC AS=$AS RANLIB=$RANLIB AR=$AR WINDRES=$WINDRES STRIP=$STRIP -f Makefile.w32 $* �������������������quakespasm-0.91.0/Quake/image.c���������������������������������������������������������������������0000644�0000000�0000000�00000026444�12407762022�014761� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //image.c -- image loading #include "quakedef.h" static char loadfilename[MAX_OSPATH]; //file scope so that error messages can use it typedef struct stdio_buffer_s { FILE *f; unsigned char buffer[1024]; int size; int pos; } stdio_buffer_t; static stdio_buffer_t *Buf_Alloc(FILE *f) { stdio_buffer_t *buf = (stdio_buffer_t *) calloc(1, sizeof(stdio_buffer_t)); buf->f = f; return buf; } static void Buf_Free(stdio_buffer_t *buf) { free(buf); } static inline int Buf_GetC(stdio_buffer_t *buf) { if (buf->pos >= buf->size) { buf->size = fread(buf->buffer, 1, sizeof(buf->buffer), buf->f); buf->pos = 0; if (buf->size == 0) return EOF; } return buf->buffer[buf->pos++]; } /* ============ Image_LoadImage returns a pointer to hunk allocated RGBA data TODO: search order: tga png jpg pcx lmp ============ */ byte *Image_LoadImage (const char *name, int *width, int *height) { FILE *f; q_snprintf (loadfilename, sizeof(loadfilename), "%s.tga", name); COM_FOpenFile (loadfilename, &f, NULL); if (f) return Image_LoadTGA (f, width, height); q_snprintf (loadfilename, sizeof(loadfilename), "%s.pcx", name); COM_FOpenFile (loadfilename, &f, NULL); if (f) return Image_LoadPCX (f, width, height); return NULL; } //============================================================================== // // TGA // //============================================================================== typedef struct targaheader_s { unsigned char id_length, colormap_type, image_type; unsigned short colormap_index, colormap_length; unsigned char colormap_size; unsigned short x_origin, y_origin, width, height; unsigned char pixel_size, attributes; } targaheader_t; #define TARGAHEADERSIZE 18 //size on disk targaheader_t targa_header; int fgetLittleShort (FILE *f) { byte b1, b2; b1 = fgetc(f); b2 = fgetc(f); return (short)(b1 + b2*256); } int fgetLittleLong (FILE *f) { byte b1, b2, b3, b4; b1 = fgetc(f); b2 = fgetc(f); b3 = fgetc(f); b4 = fgetc(f); return b1 + (b2<<8) + (b3<<16) + (b4<<24); } /* ============ Image_WriteTGA -- writes RGB or RGBA data to a TGA file returns true if successful TODO: support BGRA and BGR formats (since opengl can return them, and we don't have to swap) ============ */ qboolean Image_WriteTGA (const char *name, byte *data, int width, int height, int bpp, qboolean upsidedown) { int handle, i, size, temp, bytes; char pathname[MAX_OSPATH]; byte header[TARGAHEADERSIZE]; Sys_mkdir (com_gamedir); //if we've switched to a nonexistant gamedir, create it now so we don't crash q_snprintf (pathname, sizeof(pathname), "%s/%s", com_gamedir, name); handle = Sys_FileOpenWrite (pathname); if (handle == -1) return false; Q_memset (&header, 0, TARGAHEADERSIZE); header[2] = 2; // uncompressed type header[12] = width&255; header[13] = width>>8; header[14] = height&255; header[15] = height>>8; header[16] = bpp; // pixel size if (upsidedown) header[17] = 0x20; //upside-down attribute // swap red and blue bytes bytes = bpp/8; size = width*height*bytes; for (i=0; i<size; i+=bytes) { temp = data[i]; data[i] = data[i+2]; data[i+2] = temp; } Sys_FileWrite (handle, &header, TARGAHEADERSIZE); Sys_FileWrite (handle, data, size); Sys_FileClose (handle); return true; } /* ============= Image_LoadTGA ============= */ byte *Image_LoadTGA (FILE *fin, int *width, int *height) { int columns, rows, numPixels; byte *pixbuf; int row, column; byte *targa_rgba; int realrow; //johnfitz -- fix for upside-down targas qboolean upside_down; //johnfitz -- fix for upside-down targas stdio_buffer_t *buf; targa_header.id_length = fgetc(fin); targa_header.colormap_type = fgetc(fin); targa_header.image_type = fgetc(fin); targa_header.colormap_index = fgetLittleShort(fin); targa_header.colormap_length = fgetLittleShort(fin); targa_header.colormap_size = fgetc(fin); targa_header.x_origin = fgetLittleShort(fin); targa_header.y_origin = fgetLittleShort(fin); targa_header.width = fgetLittleShort(fin); targa_header.height = fgetLittleShort(fin); targa_header.pixel_size = fgetc(fin); targa_header.attributes = fgetc(fin); if (targa_header.image_type!=2 && targa_header.image_type!=10) Sys_Error ("Image_LoadTGA: %s is not a type 2 or type 10 targa\n", loadfilename); if (targa_header.colormap_type !=0 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) Sys_Error ("Image_LoadTGA: %s is not a 24bit or 32bit targa\n", loadfilename); columns = targa_header.width; rows = targa_header.height; numPixels = columns * rows; upside_down = !(targa_header.attributes & 0x20); //johnfitz -- fix for upside-down targas targa_rgba = (byte *) Hunk_Alloc (numPixels*4); if (targa_header.id_length != 0) fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment buf = Buf_Alloc(fin); if (targa_header.image_type==2) // Uncompressed, RGB images { for(row=rows-1; row>=0; row--) { //johnfitz -- fix for upside-down targas realrow = upside_down ? row : rows - 1 - row; pixbuf = targa_rgba + realrow*columns*4; //johnfitz for(column=0; column<columns; column++) { unsigned char red,green,blue,alphabyte; switch (targa_header.pixel_size) { case 24: blue = Buf_GetC(buf); green = Buf_GetC(buf); red = Buf_GetC(buf); *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = Buf_GetC(buf); green = Buf_GetC(buf); red = Buf_GetC(buf); alphabyte = Buf_GetC(buf); *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; break; } } } } else if (targa_header.image_type==10) // Runlength encoded RGB images { unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; for(row=rows-1; row>=0; row--) { //johnfitz -- fix for upside-down targas realrow = upside_down ? row : rows - 1 - row; pixbuf = targa_rgba + realrow*columns*4; //johnfitz for(column=0; column<columns; ) { packetHeader=Buf_GetC(buf); packetSize = 1 + (packetHeader & 0x7f); if (packetHeader & 0x80) // run-length packet { switch (targa_header.pixel_size) { case 24: blue = Buf_GetC(buf); green = Buf_GetC(buf); red = Buf_GetC(buf); alphabyte = 255; break; case 32: blue = Buf_GetC(buf); green = Buf_GetC(buf); red = Buf_GetC(buf); alphabyte = Buf_GetC(buf); break; default: /* avoid compiler warnings */ blue = red = green = alphabyte = 0; } for(j=0;j<packetSize;j++) { *pixbuf++=red; *pixbuf++=green; *pixbuf++=blue; *pixbuf++=alphabyte; column++; if (column==columns) // run spans across rows { column=0; if (row>0) row--; else goto breakOut; //johnfitz -- fix for upside-down targas realrow = upside_down ? row : rows - 1 - row; pixbuf = targa_rgba + realrow*columns*4; //johnfitz } } } else // non run-length packet { for(j=0;j<packetSize;j++) { switch (targa_header.pixel_size) { case 24: blue = Buf_GetC(buf); green = Buf_GetC(buf); red = Buf_GetC(buf); *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = Buf_GetC(buf); green = Buf_GetC(buf); red = Buf_GetC(buf); alphabyte = Buf_GetC(buf); *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; break; default: /* avoid compiler warnings */ blue = red = green = alphabyte = 0; } column++; if (column==columns) // pixel packet run spans across rows { column=0; if (row>0) row--; else goto breakOut; //johnfitz -- fix for upside-down targas realrow = upside_down ? row : rows - 1 - row; pixbuf = targa_rgba + realrow*columns*4; //johnfitz } } } } breakOut:; } } Buf_Free(buf); fclose(fin); *width = (int)(targa_header.width); *height = (int)(targa_header.height); return targa_rgba; } //============================================================================== // // PCX // //============================================================================== typedef struct { char signature; char version; char encoding; char bits_per_pixel; unsigned short xmin,ymin,xmax,ymax; unsigned short hdpi,vdpi; byte colortable[48]; char reserved; char color_planes; unsigned short bytes_per_line; unsigned short palette_type; char filler[58]; } pcxheader_t; /* ============ Image_LoadPCX ============ */ byte *Image_LoadPCX (FILE *f, int *width, int *height) { pcxheader_t pcx; int x, y, w, h, readbyte, runlength, start; byte *p, *data; byte palette[768]; stdio_buffer_t *buf; start = ftell (f); //save start of file (since we might be inside a pak file, SEEK_SET might not be the start of the pcx) fread(&pcx, sizeof(pcx), 1, f); pcx.xmin = (unsigned short)LittleShort (pcx.xmin); pcx.ymin = (unsigned short)LittleShort (pcx.ymin); pcx.xmax = (unsigned short)LittleShort (pcx.xmax); pcx.ymax = (unsigned short)LittleShort (pcx.ymax); pcx.bytes_per_line = (unsigned short)LittleShort (pcx.bytes_per_line); if (pcx.signature != 0x0A) Sys_Error ("'%s' is not a valid PCX file", loadfilename); if (pcx.version != 5) Sys_Error ("'%s' is version %i, should be 5", loadfilename, pcx.version); if (pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcx.color_planes != 1) Sys_Error ("'%s' has wrong encoding or bit depth", loadfilename); w = pcx.xmax - pcx.xmin + 1; h = pcx.ymax - pcx.ymin + 1; data = (byte *) Hunk_Alloc((w*h+1)*4); //+1 to allow reading padding byte on last line //load palette fseek (f, start + com_filesize - 768, SEEK_SET); fread (palette, 1, 768, f); //back to start of image data fseek (f, start + sizeof(pcx), SEEK_SET); buf = Buf_Alloc(f); for (y=0; y<h; y++) { p = data + y * w * 4; for (x=0; x<(pcx.bytes_per_line); ) //read the extra padding byte if necessary { readbyte = Buf_GetC(buf); if(readbyte >= 0xC0) { runlength = readbyte & 0x3F; readbyte = Buf_GetC(buf); } else runlength = 1; while(runlength--) { p[0] = palette[readbyte*3]; p[1] = palette[readbyte*3+1]; p[2] = palette[readbyte*3+2]; p[3] = 255; p += 4; x++; } } } Buf_Free(buf); fclose(f); *width = w; *height = h; return data; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_wave.h������������������������������������������������������������������0000644�0000000�0000000�00000000313�11511145623�015472� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* WAV streaming music support. */ #if !defined(_SND_WAVE_H_) #define _SND_WAVE_H_ #if defined(USE_CODEC_WAVE) extern snd_codec_t wav_codec; #endif /* USE_CODEC_WAVE */ #endif /* ! _SND_WAVE_H_ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sys_sdl_unix.c��������������������������������������������������������������0000644�0000000�0000000�00000022324�12425643172�016417� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "arch_def.h" #include "quakedef.h" #include <sys/types.h> #include <errno.h> #include <unistd.h> #ifdef PLATFORM_OSX #include <libgen.h> /* dirname() and basename() */ #endif #include <sys/stat.h> #include <sys/time.h> #include <fcntl.h> #include <time.h> #ifdef DO_USERDIRS #include <pwd.h> #endif #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif qboolean isDedicated; cvar_t sys_throttle = {"sys_throttle", "0.02", CVAR_ARCHIVE}; #define MAX_HANDLES 32 /* johnfitz -- was 10 */ static FILE *sys_handles[MAX_HANDLES]; static int findhandle (void) { int i; for (i = 1; i < MAX_HANDLES; i++) { if (!sys_handles[i]) return i; } Sys_Error ("out of handles"); return -1; } long Sys_filelength (FILE *f) { long pos, end; pos = ftell (f); fseek (f, 0, SEEK_END); end = ftell (f); fseek (f, pos, SEEK_SET); return end; } int Sys_FileOpenRead (const char *path, int *hndl) { FILE *f; int i, retval; i = findhandle (); f = fopen(path, "rb"); if (!f) { *hndl = -1; retval = -1; } else { sys_handles[i] = f; *hndl = i; retval = Sys_filelength(f); } return retval; } int Sys_FileOpenWrite (const char *path) { FILE *f; int i; i = findhandle (); f = fopen(path, "wb"); if (!f) Sys_Error ("Error opening %s: %s", path, strerror(errno)); sys_handles[i] = f; return i; } void Sys_FileClose (int handle) { fclose (sys_handles[handle]); sys_handles[handle] = NULL; } void Sys_FileSeek (int handle, int position) { fseek (sys_handles[handle], position, SEEK_SET); } int Sys_FileRead (int handle, void *dest, int count) { return fread (dest, 1, count, sys_handles[handle]); } int Sys_FileWrite (int handle, const void *data, int count) { return fwrite (data, 1, count, sys_handles[handle]); } int Sys_FileTime (const char *path) { FILE *f; f = fopen(path, "rb"); if (f) { fclose(f); return 1; } return -1; } #if defined(__linux__) || defined(__sun) || defined(sun) || defined(_AIX) static int Sys_NumCPUs (void) { int numcpus = sysconf(_SC_NPROCESSORS_ONLN); return (numcpus < 1) ? 1 : numcpus; } #elif defined(PLATFORM_OSX) #include <sys/sysctl.h> #if !defined(HW_AVAILCPU) /* using an ancient SDK? */ #define HW_AVAILCPU 25 /* needs >= 10.2 */ #endif static int Sys_NumCPUs (void) { int numcpus; int mib[2]; size_t len; #if defined(_SC_NPROCESSORS_ONLN) /* needs >= 10.5 */ numcpus = sysconf(_SC_NPROCESSORS_ONLN); if (numcpus != -1) return (numcpus < 1) ? 1 : numcpus; #endif len = sizeof(numcpus); mib[0] = CTL_HW; mib[1] = HW_AVAILCPU; sysctl(mib, 2, &numcpus, &len, NULL, 0); if (sysctl(mib, 2, &numcpus, &len, NULL, 0) == -1) { mib[1] = HW_NCPU; if (sysctl(mib, 2, &numcpus, &len, NULL, 0) == -1) return 1; } return (numcpus < 1) ? 1 : numcpus; } #elif defined(__sgi) || defined(sgi) || defined(__sgi__) /* IRIX */ static int Sys_NumCPUs (void) { int numcpus = sysconf(_SC_NPROC_ONLN); if (numcpus < 1) numcpus = 1; return numcpus; } #elif defined(PLATFORM_BSD) #include <sys/sysctl.h> static int Sys_NumCPUs (void) { int numcpus; int mib[2]; size_t len; #if defined(_SC_NPROCESSORS_ONLN) numcpus = sysconf(_SC_NPROCESSORS_ONLN); if (numcpus != -1) return (numcpus < 1) ? 1 : numcpus; #endif len = sizeof(numcpus); mib[0] = CTL_HW; mib[1] = HW_NCPU; if (sysctl(mib, 2, &numcpus, &len, NULL, 0) == -1) return 1; return (numcpus < 1) ? 1 : numcpus; } #elif defined(__hpux) || defined(__hpux__) || defined(_hpux) #include <sys/mpctl.h> static int Sys_NumCPUs (void) { int numcpus = mpctl(MPC_GETNUMSPUS, NULL, NULL); return numcpus; } #else /* unknown OS */ static int Sys_NumCPUs (void) { return -2; } #endif static char cwd[MAX_OSPATH]; #ifdef DO_USERDIRS static char userdir[MAX_OSPATH]; #ifdef PLATFORM_OSX #define SYS_USERDIR "Library/Application Support/QuakeSpasm" #else #define SYS_USERDIR ".quakespasm" #endif static void Sys_GetUserdir (char *dst, size_t dstsize) { size_t n; const char *home_dir = NULL; struct passwd *pwent; pwent = getpwuid( getuid() ); if (pwent == NULL) perror("getpwuid"); else home_dir = pwent->pw_dir; if (home_dir == NULL) home_dir = getenv("HOME"); if (home_dir == NULL) Sys_Error ("Couldn't determine userspace directory"); /* what would be a maximum path for a file in the user's directory... * $HOME/SYS_USERDIR/game_dir/dirname1/dirname2/dirname3/filename.ext * still fits in the MAX_OSPATH == 256 definition, but just in case : */ n = strlen(home_dir) + strlen(SYS_USERDIR) + 50; if (n >= dstsize) Sys_Error ("Insufficient array size for userspace directory"); q_snprintf (dst, dstsize, "%s/%s", home_dir, SYS_USERDIR); } #endif /* DO_USERDIRS */ #ifdef PLATFORM_OSX static char *OSX_StripAppBundle (char *dir) { /* based on the ioquake3 project at icculus.org. */ static char osx_path[MAX_OSPATH]; q_strlcpy (osx_path, dir, sizeof(osx_path)); if (strcmp(basename(osx_path), "MacOS")) return dir; q_strlcpy (osx_path, dirname(osx_path), sizeof(osx_path)); if (strcmp(basename(osx_path), "Contents")) return dir; q_strlcpy (osx_path, dirname(osx_path), sizeof(osx_path)); if (!strstr(basename(osx_path), ".app")) return dir; q_strlcpy (osx_path, dirname(osx_path), sizeof(osx_path)); return osx_path; } static void Sys_GetBasedir (char *argv0, char *dst, size_t dstsize) { char *tmp; if (realpath(argv0, dst) == NULL) { perror("realpath"); if (getcwd(dst, dstsize - 1) == NULL) _fail: Sys_Error ("Couldn't determine current directory"); } else { /* strip off the binary name */ if (! (tmp = strdup (dst))) goto _fail; q_strlcpy (dst, dirname(tmp), dstsize); free (tmp); } tmp = OSX_StripAppBundle(dst); if (tmp != dst) q_strlcpy (dst, tmp, dstsize); } #else static void Sys_GetBasedir (char *argv0, char *dst, size_t dstsize) { char *tmp; if (getcwd(dst, dstsize - 1) == NULL) Sys_Error ("Couldn't determine current directory"); tmp = dst; while (*tmp != 0) tmp++; while (*tmp == 0 && tmp != dst) { --tmp; if (tmp != dst && *tmp == '/') *tmp = 0; } } #endif void Sys_Init (void) { memset (cwd, 0, sizeof(cwd)); Sys_GetBasedir(host_parms->argv[0], cwd, sizeof(cwd)); host_parms->basedir = cwd; #ifndef DO_USERDIRS host_parms->userdir = host_parms->basedir; /* code elsewhere relies on this ! */ #else memset (userdir, 0, sizeof(userdir)); Sys_GetUserdir(userdir, sizeof(userdir)); Sys_mkdir (userdir); host_parms->userdir = userdir; #endif host_parms->numcpus = Sys_NumCPUs (); Sys_Printf("Detected %d CPUs.\n", host_parms->numcpus); } void Sys_mkdir (const char *path) { int rc = mkdir (path, 0777); if (rc != 0 && errno == EEXIST) { struct stat st; if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) rc = 0; } if (rc != 0) { rc = errno; Sys_Error("Unable to create directory %s: %s", path, strerror(rc)); } } static const char errortxt1[] = "\nERROR-OUT BEGIN\n\n"; static const char errortxt2[] = "\nQUAKE ERROR: "; void Sys_Error (const char *error, ...) { va_list argptr; char text[1024]; fputs (errortxt1, stderr); Host_Shutdown (); va_start (argptr, error); q_vsnprintf (text, sizeof(text), error, argptr); va_end (argptr); fputs (errortxt2, stderr); fputs (text, stderr); fputs ("\n\n", stderr); if (!isDedicated) PL_ErrorDialog(text); exit (1); } void Sys_Printf (const char *fmt, ...) { va_list argptr; va_start(argptr, fmt); vprintf(fmt, argptr); va_end(argptr); } void Sys_Quit (void) { Host_Shutdown(); exit (0); } double Sys_DoubleTime (void) { return SDL_GetTicks() / 1000.0; } const char *Sys_ConsoleInput (void) { static char con_text[256]; static int textlen; char c; fd_set set; struct timeval timeout; FD_ZERO (&set); FD_SET (0, &set); // stdin timeout.tv_sec = 0; timeout.tv_usec = 0; while (select (1, &set, NULL, NULL, &timeout)) { read (0, &c, 1); if (c == '\n' || c == '\r') { con_text[textlen] = '\0'; textlen = 0; return con_text; } else if (c == 8) { if (textlen) { textlen--; con_text[textlen] = '\0'; } continue; } con_text[textlen] = c; textlen++; if (textlen < (int) sizeof(con_text)) con_text[textlen] = '\0'; else { // buffer is full textlen = 0; con_text[0] = '\0'; Sys_Printf("\nConsole input too long!\n"); break; } } return NULL; } void Sys_Sleep (unsigned long msecs) { /* usleep (msecs * 1000);*/ SDL_Delay (msecs); } void Sys_SendKeyEvents (void) { IN_SendKeyEvents(); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/net_loop.h������������������������������������������������������������������0000644�0000000�0000000�00000002552�12407762022�015515� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __NET_LOOP_H #define __NET_LOOP_H // net_loop.h int Loop_Init (void); void Loop_Listen (qboolean state); void Loop_SearchForHosts (qboolean xmit); qsocket_t *Loop_Connect (const char *host); qsocket_t *Loop_CheckNewConnections (void); int Loop_GetMessage (qsocket_t *sock); int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data); int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data); qboolean Loop_CanSendMessage (qsocket_t *sock); qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock); void Loop_Close (qsocket_t *sock); void Loop_Shutdown (void); #endif /* __NET_LOOP_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/console.h�������������������������������������������������������������������0000644�0000000�0000000�00000004350�12530477523�015344� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __CONSOLE_H #define __CONSOLE_H // // console // extern int con_totallines; extern int con_backscroll; extern qboolean con_forcedup; // because no entities to refresh extern qboolean con_initialized; extern byte *con_chars; extern char con_lastcenterstring[]; //johnfitz void Con_DrawCharacter (int cx, int line, int num); void Con_CheckResize (void); void Con_Init (void); void Con_DrawConsole (int lines, qboolean drawinput); void Con_Printf (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); void Con_DWarning (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); //ericw void Con_Warning (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); //johnfitz void Con_DPrintf (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); void Con_DPrintf2 (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); //johnfitz void Con_SafePrintf (const char *fmt, ...) __attribute__((__format__(__printf__,1,2))); void Con_DrawNotify (void); void Con_ClearNotify (void); void Con_ToggleConsole_f (void); void Con_NotifyBox (const char *text); // during startup for sound / cd warnings void Con_Show (void); void Con_Hide (void); const char *Con_Quakebar (int len); void Con_TabComplete (void); void Con_LogCenterPrint (const char *str); // // debuglog // void LOG_Init (quakeparms_t *parms); void LOG_Close (void); void Con_DebugLog (const char *msg); #endif /* __CONSOLE_H */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/q_ctype.h�������������������������������������������������������������������0000644�0000000�0000000�00000003567�12220613364�015346� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Locale insensitive ctype.h functions taken from the RPM library - * RPM is Copyright (c) 1998 by Red Hat Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 */ #ifndef Q_CTYPE_H #define Q_CTYPE_H static inline int q_isascii(int c) { return ((c & ~0x7f) == 0); } static inline int q_islower(int c) { return (c >= 'a' && c <= 'z'); } static inline int q_isupper(int c) { return (c >= 'A' && c <= 'Z'); } static inline int q_isalpha(int c) { return (q_islower(c) || q_isupper(c)); } static inline int q_isdigit(int c) { return (c >= '0' && c <= '9'); } static inline int q_isxdigit(int c) { return (q_isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } static inline int q_isalnum(int c) { return (q_isalpha(c) || q_isdigit(c)); } static inline int q_isblank(int c) { return (c == ' ' || c == '\t'); } static inline int q_isspace(int c) { return (q_isblank(c) || c == '\n' || c == '\r' || c == '\f' || c == '\v'); } static inline int q_toascii(int c) { return (c & 0x7f); } static inline int q_tolower(int c) { return ((q_isupper(c)) ? (c | ('a' - 'A')) : c); } static inline int q_toupper(int c) { return ((q_islower(c)) ? (c & ~('a' - 'A')) : c); } #endif /* Q_CTYPE_H */ �����������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/chase.c���������������������������������������������������������������������0000644�0000000�0000000�00000006130�12407762022�014750� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // chase.c -- chase camera code #include "quakedef.h" cvar_t chase_back = {"chase_back", "100", CVAR_NONE}; cvar_t chase_up = {"chase_up", "16", CVAR_NONE}; cvar_t chase_right = {"chase_right", "0", CVAR_NONE}; cvar_t chase_active = {"chase_active", "0", CVAR_NONE}; /* ============== Chase_Init ============== */ void Chase_Init (void) { Cvar_RegisterVariable (&chase_back); Cvar_RegisterVariable (&chase_up); Cvar_RegisterVariable (&chase_right); Cvar_RegisterVariable (&chase_active); } /* ============== TraceLine TODO: impact on bmodels, monsters ============== */ void TraceLine (vec3_t start, vec3_t end, vec3_t impact) { trace_t trace; memset (&trace, 0, sizeof(trace)); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); VectorCopy (trace.endpos, impact); } /* ============== Chase_UpdateForClient -- johnfitz -- orient client based on camera. called after input ============== */ void Chase_UpdateForClient (void) { //place camera //assign client angles to camera //see where camera points //adjust client angles to point at the same place } /* ============== Chase_UpdateForDrawing -- johnfitz -- orient camera based on client. called before drawing TODO: stay at least 8 units away from all walls in this leaf ============== */ void Chase_UpdateForDrawing (void) { int i; vec3_t forward, up, right; vec3_t ideal, crosshair, temp; AngleVectors (cl.viewangles, forward, right, up); // calc ideal camera location before checking for walls for (i=0 ; i<3 ; i++) ideal[i] = cl.viewent.origin[i] - forward[i]*chase_back.value + right[i]*chase_right.value; //+ up[i]*chase_up.value; ideal[2] = cl.viewent.origin[2] + chase_up.value; // make sure camera is not in or behind a wall TraceLine(r_refdef.vieworg, ideal, temp); if (VectorLength(temp) != 0) VectorCopy(temp, ideal); // place camera VectorCopy (ideal, r_refdef.vieworg); // find the spot the player is looking at VectorMA (cl.viewent.origin, 4096, forward, temp); TraceLine (cl.viewent.origin, temp, crosshair); // calculate camera angles to look at the same spot VectorSubtract (crosshair, r_refdef.vieworg, temp); VectorAngles (temp, r_refdef.viewangles); if (r_refdef.viewangles[PITCH] == 90 || r_refdef.viewangles[PITCH] == -90) r_refdef.viewangles[YAW] = cl.viewangles[YAW]; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/common.h��������������������������������������������������������������������0000644�0000000�0000000�00000023157�12407762022�015172� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _Q_COMMON_H #define _Q_COMMON_H // comndef.h -- general definitions #if defined(_WIN32) #ifdef _MSC_VER # pragma warning(disable:4244) /* 'argument' : conversion from 'type1' to 'type2', possible loss of data */ # pragma warning(disable:4305) /* 'identifier' : truncation from 'type1' to 'type2' */ /* in our case, truncation from 'double' to 'float' */ # pragma warning(disable:4267) /* 'var' : conversion from 'size_t' to 'type', possible loss of data (/Wp64 warning) */ #endif /* _MSC_VER */ #endif /* _WIN32 */ #undef min #undef max #define q_min(a, b) (((a) < (b)) ? (a) : (b)) #define q_max(a, b) (((a) > (b)) ? (a) : (b)) #define CLAMP(_minval, x, _maxval) \ ((x) < (_minval) ? (_minval) : \ (x) > (_maxval) ? (_maxval) : (x)) typedef struct sizebuf_s { qboolean allowoverflow; // if false, do a Sys_Error qboolean overflowed; // set to true if the buffer size failed byte *data; int maxsize; int cursize; } sizebuf_t; void SZ_Alloc (sizebuf_t *buf, int startsize); void SZ_Free (sizebuf_t *buf); void SZ_Clear (sizebuf_t *buf); void *SZ_GetSpace (sizebuf_t *buf, int length); void SZ_Write (sizebuf_t *buf, const void *data, int length); void SZ_Print (sizebuf_t *buf, const char *data); // strcats onto the sizebuf //============================================================================ typedef struct link_s { struct link_s *prev, *next; } link_t; void ClearLink (link_t *l); void RemoveLink (link_t *l); void InsertLinkBefore (link_t *l, link_t *before); void InsertLinkAfter (link_t *l, link_t *after); // (type *)STRUCT_FROM_LINK(link_t *link, type, member) // ent = STRUCT_FROM_LINK(link,entity_t,order) // FIXME: remove this mess! #define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (intptr_t)&(((t *)0)->m))) //============================================================================ extern qboolean host_bigendian; extern short (*BigShort) (short l); extern short (*LittleShort) (short l); extern int (*BigLong) (int l); extern int (*LittleLong) (int l); extern float (*BigFloat) (float l); extern float (*LittleFloat) (float l); //============================================================================ void MSG_WriteChar (sizebuf_t *sb, int c); void MSG_WriteByte (sizebuf_t *sb, int c); void MSG_WriteShort (sizebuf_t *sb, int c); void MSG_WriteLong (sizebuf_t *sb, int c); void MSG_WriteFloat (sizebuf_t *sb, float f); void MSG_WriteString (sizebuf_t *sb, const char *s); void MSG_WriteCoord (sizebuf_t *sb, float f); void MSG_WriteAngle (sizebuf_t *sb, float f); void MSG_WriteAngle16 (sizebuf_t *sb, float f); //johnfitz extern int msg_readcount; extern qboolean msg_badread; // set if a read goes beyond end of message void MSG_BeginReading (void); int MSG_ReadChar (void); int MSG_ReadByte (void); int MSG_ReadShort (void); int MSG_ReadLong (void); float MSG_ReadFloat (void); const char *MSG_ReadString (void); float MSG_ReadCoord (void); float MSG_ReadAngle (void); float MSG_ReadAngle16 (void); //johnfitz //============================================================================ void Q_memset (void *dest, int fill, size_t count); void Q_memcpy (void *dest, const void *src, size_t count); int Q_memcmp (const void *m1, const void *m2, size_t count); void Q_strcpy (char *dest, const char *src); void Q_strncpy (char *dest, const char *src, int count); int Q_strlen (const char *str); char *Q_strrchr (const char *s, char c); void Q_strcat (char *dest, const char *src); int Q_strcmp (const char *s1, const char *s2); int Q_strncmp (const char *s1, const char *s2, int count); int Q_atoi (const char *str); float Q_atof (const char *str); #include "strl_fn.h" /* locale-insensitive strcasecmp replacement functions: */ extern int q_strcasecmp (const char * s1, const char * s2); extern int q_strncasecmp (const char *s1, const char *s2, size_t n); /* locale-insensitive strlwr/upr replacement functions: */ extern char *q_strlwr (char *str); extern char *q_strupr (char *str); /* snprintf, vsnprintf : always use our versions. */ extern int q_snprintf (char *str, size_t size, const char *format, ...) __attribute__((__format__(__printf__,3,4))); extern int q_vsnprintf(char *str, size_t size, const char *format, va_list args) __attribute__((__format__(__printf__,3,0))); //============================================================================ extern char com_token[1024]; extern qboolean com_eof; const char *COM_Parse (const char *data); extern int com_argc; extern char **com_argv; extern int safemode; /* safe mode: in true, the engine will behave as if one of these arguments were actually on the command line: -nosound, -nocdaudio, -nomidi, -stdvid, -dibonly, -nomouse, -nojoy, -nolan */ int COM_CheckParm (const char *parm); void COM_Init (void); void COM_InitArgv (int argc, char **argv); void COM_InitFilesystem (void); const char *COM_SkipPath (const char *pathname); void COM_StripExtension (const char *in, char *out, size_t outsize); void COM_FileBase (const char *in, char *out, size_t outsize); void COM_AddExtension (char *path, const char *extension, size_t len); #if 0 /* COM_DefaultExtension can be dangerous */ void COM_DefaultExtension (char *path, const char *extension, size_t len); #endif const char *COM_FileGetExtension (const char *in); /* doesn't return NULL */ void COM_ExtractExtension (const char *in, char *out, size_t outsize); void COM_CreatePath (char *path); char *va (const char *format, ...) __attribute__((__format__(__printf__,1,2))); // does a varargs printf into a temp buffer //============================================================================ // QUAKEFS typedef struct { char name[MAX_QPATH]; int filepos, filelen; } packfile_t; typedef struct pack_s { char filename[MAX_OSPATH]; int handle; int numfiles; packfile_t *files; } pack_t; typedef struct searchpath_s { unsigned int path_id; // identifier assigned to the game directory // Note that <install_dir>/game1 and // <userdir>/game1 have the same id. char filename[MAX_OSPATH]; pack_t *pack; // only one of filename / pack will be used struct searchpath_s *next; } searchpath_t; extern searchpath_t *com_searchpaths; extern searchpath_t *com_base_searchpaths; extern int com_filesize; struct cache_user_s; extern char com_basedir[MAX_OSPATH]; extern char com_gamedir[MAX_OSPATH]; extern int file_from_pak; // global indicating that file came from a pak void COM_WriteFile (const char *filename, const void *data, int len); int COM_OpenFile (const char *filename, int *handle, unsigned int *path_id); int COM_FOpenFile (const char *filename, FILE **file, unsigned int *path_id); qboolean COM_FileExists (const char *filename, unsigned int *path_id); void COM_CloseFile (int h); // these procedures open a file using COM_FindFile and loads it into a proper // buffer. the buffer is allocated with a total size of com_filesize + 1. the // procedures differ by their buffer allocation method. byte *COM_LoadStackFile (const char *path, void *buffer, int bufsize, unsigned int *path_id); // uses the specified stack stack buffer with the specified size // of bufsize. if bufsize is too short, uses temp hunk. the bufsize // must include the +1 byte *COM_LoadTempFile (const char *path, unsigned int *path_id); // allocates the buffer on the temp hunk. byte *COM_LoadHunkFile (const char *path, unsigned int *path_id); // allocates the buffer on the hunk. byte *COM_LoadZoneFile (const char *path, unsigned int *path_id); // allocates the buffer on the zone. void COM_LoadCacheFile (const char *path, struct cache_user_s *cu, unsigned int *path_id); // uses cache mem for allocating the buffer. byte *COM_LoadMallocFile (const char *path, unsigned int *path_id); // allocates the buffer on the system mem (malloc). /* The following FS_*() stdio replacements are necessary if one is * to perform non-sequential reads on files reopened on pak files * because we need the bookkeeping about file start/end positions. * Allocating and filling in the fshandle_t structure is the users' * responsibility when the file is initially opened. */ typedef struct _fshandle_t { FILE *file; qboolean pak; /* is the file read from a pak */ long start; /* file or data start position */ long length; /* file or data size */ long pos; /* current position relative to start */ } fshandle_t; size_t FS_fread(void *ptr, size_t size, size_t nmemb, fshandle_t *fh); int FS_fseek(fshandle_t *fh, long offset, int whence); long FS_ftell(fshandle_t *fh); void FS_rewind(fshandle_t *fh); int FS_feof(fshandle_t *fh); int FS_ferror(fshandle_t *fh); int FS_fclose(fshandle_t *fh); int FS_fgetc(fshandle_t *fh); char *FS_fgets(char *s, int size, fshandle_t *fh); long FS_filelength (fshandle_t *fh); extern struct cvar_s registered; extern qboolean standard_quake, rogue, hipnotic; extern qboolean fitzmode; /* if true, run in fitzquake mode disabling custom quakespasm hacks */ #endif /* _Q_COMMON_H */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/sys_sdl_win.c���������������������������������������������������������������0000644�0000000�0000000�00000021751�12573372527�016243� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> #include <mmsystem.h> #include "quakedef.h" #include <sys/types.h> #include <errno.h> #include <io.h> #include <direct.h> #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif qboolean isDedicated; qboolean Win95, Win95old, WinNT, WinVista; cvar_t sys_throttle = {"sys_throttle", "0.02", CVAR_ARCHIVE}; static HANDLE hinput, houtput; #define MAX_HANDLES 32 /* johnfitz -- was 10 */ static FILE *sys_handles[MAX_HANDLES]; static int findhandle (void) { int i; for (i = 1; i < MAX_HANDLES; i++) { if (!sys_handles[i]) return i; } Sys_Error ("out of handles"); return -1; } long Sys_filelength (FILE *f) { long pos, end; pos = ftell (f); fseek (f, 0, SEEK_END); end = ftell (f); fseek (f, pos, SEEK_SET); return end; } int Sys_FileOpenRead (const char *path, int *hndl) { FILE *f; int i, retval; i = findhandle (); f = fopen(path, "rb"); if (!f) { *hndl = -1; retval = -1; } else { sys_handles[i] = f; *hndl = i; retval = Sys_filelength(f); } return retval; } int Sys_FileOpenWrite (const char *path) { FILE *f; int i; i = findhandle (); f = fopen(path, "wb"); if (!f) Sys_Error ("Error opening %s: %s", path, strerror(errno)); sys_handles[i] = f; return i; } void Sys_FileClose (int handle) { fclose (sys_handles[handle]); sys_handles[handle] = NULL; } void Sys_FileSeek (int handle, int position) { fseek (sys_handles[handle], position, SEEK_SET); } int Sys_FileRead (int handle, void *dest, int count) { return fread (dest, 1, count, sys_handles[handle]); } int Sys_FileWrite (int handle, const void *data, int count) { return fwrite (data, 1, count, sys_handles[handle]); } int Sys_FileTime (const char *path) { FILE *f; f = fopen(path, "rb"); if (f) { fclose(f); return 1; } return -1; } static char cwd[1024]; static void Sys_GetBasedir (char *argv0, char *dst, size_t dstsize) { char *tmp; if (GetCurrentDirectory(dstsize, dst) == 0) Sys_Error ("Couldn't determine current directory"); tmp = dst; while (*tmp != 0) tmp++; while (*tmp == 0 && tmp != dst) { --tmp; if (tmp != dst && (*tmp == '/' || *tmp == '\\')) *tmp = 0; } } typedef enum { dpi_unaware = 0, dpi_system_aware = 1, dpi_monitor_aware = 2 } dpi_awareness; typedef BOOL (WINAPI *SetProcessDPIAwareFunc)(); typedef HRESULT (WINAPI *SetProcessDPIAwarenessFunc)(dpi_awareness value); static void Sys_SetDPIAware (void) { HMODULE hUser32, hShcore; SetProcessDPIAwarenessFunc setDPIAwareness; SetProcessDPIAwareFunc setDPIAware; /* Neither SDL 1.2 nor SDL 2.0.3 can handle the OS scaling our window. (e.g. https://bugzilla.libsdl.org/show_bug.cgi?id=2713) Call SetProcessDpiAwareness/SetProcessDPIAware to opt out of scaling. */ hShcore = LoadLibraryA ("Shcore.dll"); hUser32 = LoadLibraryA ("user32.dll"); setDPIAwareness = (SetProcessDPIAwarenessFunc) (hShcore ? GetProcAddress (hShcore, "SetProcessDpiAwareness") : NULL); setDPIAware = (SetProcessDPIAwareFunc) (hUser32 ? GetProcAddress (hUser32, "SetProcessDPIAware") : NULL); if (setDPIAwareness) /* Windows 8.1+ */ setDPIAwareness (dpi_monitor_aware); else if (setDPIAware) /* Windows Vista-8.0 */ setDPIAware (); if (hShcore) FreeLibrary (hShcore); if (hUser32) FreeLibrary (hUser32); } static void Sys_SetTimerResolution(void) { /* Set OS timer resolution to 1ms. Works around buffer underruns with directsound and SDL2, but also will make Sleep()/SDL_Dleay() accurate to 1ms which should help framerate stability. */ timeBeginPeriod (1); } void Sys_Init (void) { OSVERSIONINFO vinfo; Sys_SetTimerResolution (); Sys_SetDPIAware (); memset (cwd, 0, sizeof(cwd)); Sys_GetBasedir(NULL, cwd, sizeof(cwd)); host_parms->basedir = cwd; /* userdirs not really necessary for windows guys. * can be done if necessary, though... */ host_parms->userdir = host_parms->basedir; /* code elsewhere relies on this ! */ vinfo.dwOSVersionInfoSize = sizeof(vinfo); if (!GetVersionEx (&vinfo)) Sys_Error ("Couldn't get OS info"); if ((vinfo.dwMajorVersion < 4) || (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)) { Sys_Error ("QuakeSpasm requires at least Win95 or NT 4.0"); } if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { SYSTEM_INFO info; WinNT = true; if (vinfo.dwMajorVersion >= 6) WinVista = true; GetSystemInfo(&info); host_parms->numcpus = info.dwNumberOfProcessors; if (host_parms->numcpus < 1) host_parms->numcpus = 1; } else { WinNT = false; /* Win9x or WinME */ host_parms->numcpus = 1; if ((vinfo.dwMajorVersion == 4) && (vinfo.dwMinorVersion == 0)) { Win95 = true; /* Win95-gold or Win95A can't switch bpp automatically */ if (vinfo.szCSDVersion[1] != 'C' && vinfo.szCSDVersion[1] != 'B') Win95old = true; } } Sys_Printf("Detected %d CPUs.\n", host_parms->numcpus); if (isDedicated) { if (!AllocConsole ()) { isDedicated = false; /* so that we have a graphical error dialog */ Sys_Error ("Couldn't create dedicated server console"); } hinput = GetStdHandle (STD_INPUT_HANDLE); houtput = GetStdHandle (STD_OUTPUT_HANDLE); } } void Sys_mkdir (const char *path) { if (CreateDirectory(path, NULL) != 0) return; if (GetLastError() != ERROR_ALREADY_EXISTS) Sys_Error("Unable to create directory %s", path); } static const char errortxt1[] = "\nERROR-OUT BEGIN\n\n"; static const char errortxt2[] = "\nQUAKE ERROR: "; void Sys_Error (const char *error, ...) { va_list argptr; char text[1024]; DWORD dummy; va_start (argptr, error); q_vsnprintf (text, sizeof(text), error, argptr); va_end (argptr); if (isDedicated) WriteFile (houtput, errortxt1, strlen(errortxt1), &dummy, NULL); /* SDL will put these into its own stderr log, so print to stderr even in graphical mode. */ fputs (errortxt1, stderr); Host_Shutdown (); fputs (errortxt2, stderr); fputs (text, stderr); fputs ("\n\n", stderr); if (!isDedicated) PL_ErrorDialog(text); else { WriteFile (houtput, errortxt2, strlen(errortxt2), &dummy, NULL); WriteFile (houtput, text, strlen(text), &dummy, NULL); WriteFile (houtput, "\r\n", 2, &dummy, NULL); SDL_Delay (3000); /* show the console 3 more seconds */ } // shut down QHOST hooks if necessary // DeinitConProc (); exit (1); } void Sys_Printf (const char *fmt, ...) { va_list argptr; char text[1024]; DWORD dummy; va_start (argptr,fmt); q_vsnprintf (text, sizeof(text), fmt, argptr); va_end (argptr); if (isDedicated) { WriteFile(houtput, text, strlen(text), &dummy, NULL); } else { /* SDL will put these into its own stdout log, so print to stdout even in graphical mode. */ fputs (text, stdout); } } void Sys_Quit (void) { Host_Shutdown(); if (isDedicated) FreeConsole (); exit (0); } double Sys_DoubleTime (void) { return SDL_GetTicks() / 1000.0; } const char *Sys_ConsoleInput (void) { static char con_text[256]; static int textlen; INPUT_RECORD recs[1024]; int ch; DWORD dummy, numread, numevents; for ( ;; ) { if (GetNumberOfConsoleInputEvents(hinput, &numevents) == 0) Sys_Error ("Error getting # of console events"); if (numevents <= 0) break; if (ReadConsoleInput(hinput, recs, 1, &numread) == 0) Sys_Error ("Error reading console input"); if (numread != 1) Sys_Error ("Couldn't read console input"); if (recs[0].EventType == KEY_EVENT) { if (recs[0].Event.KeyEvent.bKeyDown == FALSE) { ch = recs[0].Event.KeyEvent.uChar.AsciiChar; switch (ch) { case '\r': WriteFile(houtput, "\r\n", 2, &dummy, NULL); if (textlen != 0) { con_text[textlen] = 0; textlen = 0; return con_text; } break; case '\b': WriteFile(houtput, "\b \b", 3, &dummy, NULL); if (textlen != 0) textlen--; break; default: if (ch >= ' ') { WriteFile(houtput, &ch, 1, &dummy, NULL); con_text[textlen] = ch; textlen = (textlen + 1) & 0xff; } break; } } } } return NULL; } void Sys_Sleep (unsigned long msecs) { /* Sleep (msecs);*/ SDL_Delay (msecs); } void Sys_SendKeyEvents (void) { IN_SendKeyEvents(); } �����������������������quakespasm-0.91.0/Quake/r_part.c��������������������������������������������������������������������0000644�0000000�0000000�00000052227�12514046163�015164� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #define MAX_PARTICLES 2048 // default max # of particles at one // time #define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's // on the command line int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61}; int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66}; int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3}; particle_t *active_particles, *free_particles, *particles; vec3_t r_pright, r_pup, r_ppn; int r_numparticles; gltexture_t *particletexture, *particletexture1, *particletexture2, *particletexture3, *particletexture4; //johnfitz float texturescalefactor; //johnfitz -- compensate for apparent size of different particle textures cvar_t r_particles = {"r_particles","1", CVAR_ARCHIVE}; //johnfitz cvar_t r_quadparticles = {"r_quadparticles","1", CVAR_ARCHIVE}; //johnfitz /* =============== R_ParticleTextureLookup -- johnfitz -- generate nice antialiased 32x32 circle for particles =============== */ int R_ParticleTextureLookup (int x, int y, int sharpness) { int r; //distance from point x,y to circle origin, squared int a; //alpha value to return x -= 16; y -= 16; r = x * x + y * y; r = r > 255 ? 255 : r; a = sharpness * (255 - r); a = q_min(a,255); return a; } /* =============== R_InitParticleTextures -- johnfitz -- rewritten =============== */ void R_InitParticleTextures (void) { int x,y; static byte particle1_data[64*64*4]; static byte particle2_data[2*2*4]; static byte particle3_data[64*64*4]; byte *dst; // particle texture 1 -- circle dst = particle1_data; for (x=0 ; x<64 ; x++) for (y=0 ; y<64 ; y++) { *dst++ = 255; *dst++ = 255; *dst++ = 255; *dst++ = R_ParticleTextureLookup(x, y, 8); } particletexture1 = TexMgr_LoadImage (NULL, "particle1", 64, 64, SRC_RGBA, particle1_data, "", (src_offset_t)particle1_data, TEXPREF_PERSIST | TEXPREF_ALPHA | TEXPREF_LINEAR); // particle texture 2 -- square dst = particle2_data; for (x=0 ; x<2 ; x++) for (y=0 ; y<2 ; y++) { *dst++ = 255; *dst++ = 255; *dst++ = 255; *dst++ = x || y ? 0 : 255; } particletexture2 = TexMgr_LoadImage (NULL, "particle2", 2, 2, SRC_RGBA, particle2_data, "", (src_offset_t)particle2_data, TEXPREF_PERSIST | TEXPREF_ALPHA | TEXPREF_NEAREST); // particle texture 3 -- blob dst = particle3_data; for (x=0 ; x<64 ; x++) for (y=0 ; y<64 ; y++) { *dst++ = 255; *dst++ = 255; *dst++ = 255; *dst++ = R_ParticleTextureLookup(x, y, 2); } particletexture3 = TexMgr_LoadImage (NULL, "particle3", 64, 64, SRC_RGBA, particle3_data, "", (src_offset_t)particle3_data, TEXPREF_PERSIST | TEXPREF_ALPHA | TEXPREF_LINEAR); //set default particletexture = particletexture1; texturescalefactor = 1.27; } /* =============== R_SetParticleTexture_f -- johnfitz =============== */ static void R_SetParticleTexture_f (cvar_t *var) { switch ((int)(r_particles.value)) { case 1: particletexture = particletexture1; texturescalefactor = 1.27; break; case 2: particletexture = particletexture2; texturescalefactor = 1.0; break; // case 3: // particletexture = particletexture3; // texturescalefactor = 1.5; // break; } } /* =============== R_InitParticles =============== */ void R_InitParticles (void) { int i; i = COM_CheckParm ("-particles"); if (i) { r_numparticles = (int)(Q_atoi(com_argv[i+1])); if (r_numparticles < ABSOLUTE_MIN_PARTICLES) r_numparticles = ABSOLUTE_MIN_PARTICLES; } else { r_numparticles = MAX_PARTICLES; } particles = (particle_t *) Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles"); Cvar_RegisterVariable (&r_particles); //johnfitz Cvar_SetCallback (&r_particles, R_SetParticleTexture_f); Cvar_RegisterVariable (&r_quadparticles); //johnfitz R_InitParticleTextures (); //johnfitz } /* =============== R_EntityParticles =============== */ #define NUMVERTEXNORMALS 162 extern float r_avertexnormals[NUMVERTEXNORMALS][3]; vec3_t avelocities[NUMVERTEXNORMALS]; float beamlength = 16; vec3_t avelocity = {23, 7, 3}; float partstep = 0.01; float timescale = 0.01; void R_EntityParticles (entity_t *ent) { int i; particle_t *p; float angle; float sp, sy, cp, cy; // float sr, cr; // int count; vec3_t forward; float dist; dist = 64; // count = 50; if (!avelocities[0][0]) { for (i = 0; i < NUMVERTEXNORMALS; i++) { avelocities[i][0] = (rand() & 255) * 0.01; avelocities[i][1] = (rand() & 255) * 0.01; avelocities[i][2] = (rand() & 255) * 0.01; } } for (i = 0; i < NUMVERTEXNORMALS; i++) { angle = cl.time * avelocities[i][0]; sy = sin(angle); cy = cos(angle); angle = cl.time * avelocities[i][1]; sp = sin(angle); cp = cos(angle); angle = cl.time * avelocities[i][2]; // sr = sin(angle); // cr = cos(angle); forward[0] = cp*cy; forward[1] = cp*sy; forward[2] = -sp; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->die = cl.time + 0.01; p->color = 0x6f; p->type = pt_explode; p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength; p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength; p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength; } } /* =============== R_ClearParticles =============== */ void R_ClearParticles (void) { int i; free_particles = &particles[0]; active_particles = NULL; for (i=0 ;i<r_numparticles ; i++) particles[i].next = &particles[i+1]; particles[r_numparticles-1].next = NULL; } /* =============== R_ReadPointFile_f =============== */ void R_ReadPointFile_f (void) { FILE *f; vec3_t org; int r; int c; particle_t *p; char name[MAX_QPATH]; if (cls.state != ca_connected) return; // need an active map. q_snprintf (name, sizeof(name), "maps/%s.pts", cl.mapname); COM_FOpenFile (name, &f, NULL); if (!f) { Con_Printf ("couldn't open %s\n", name); return; } Con_Printf ("Reading %s...\n", name); c = 0; for ( ;; ) { r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]); if (r != 3) break; c++; if (!free_particles) { Con_Printf ("Not enough free particles\n"); break; } p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->die = 99999; p->color = (-c)&15; p->type = pt_static; VectorCopy (vec3_origin, p->vel); VectorCopy (org, p->org); } fclose (f); Con_Printf ("%i points read\n", c); } /* =============== R_ParseParticleEffect Parse an effect out of the server message =============== */ void R_ParseParticleEffect (void) { vec3_t org, dir; int i, count, msgcount, color; for (i=0 ; i<3 ; i++) org[i] = MSG_ReadCoord (); for (i=0 ; i<3 ; i++) dir[i] = MSG_ReadChar () * (1.0/16); msgcount = MSG_ReadByte (); color = MSG_ReadByte (); if (msgcount == 255) count = 1024; else count = msgcount; R_RunParticleEffect (org, dir, color, count); } /* =============== R_ParticleExplosion =============== */ void R_ParticleExplosion (vec3_t org) { int i, j; particle_t *p; for (i=0 ; i<1024 ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->die = cl.time + 5; p->color = ramp1[0]; p->ramp = rand()&3; if (i & 1) { p->type = pt_explode; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()%32)-16); p->vel[j] = (rand()%512)-256; } } else { p->type = pt_explode2; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()%32)-16); p->vel[j] = (rand()%512)-256; } } } } /* =============== R_ParticleExplosion2 =============== */ void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength) { int i, j; particle_t *p; int colorMod = 0; for (i=0; i<512; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->die = cl.time + 0.3; p->color = colorStart + (colorMod % colorLength); colorMod++; p->type = pt_blob; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()%32)-16); p->vel[j] = (rand()%512)-256; } } } /* =============== R_BlobExplosion =============== */ void R_BlobExplosion (vec3_t org) { int i, j; particle_t *p; for (i=0 ; i<1024 ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->die = cl.time + 1 + (rand()&8)*0.05; if (i & 1) { p->type = pt_blob; p->color = 66 + rand()%6; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()%32)-16); p->vel[j] = (rand()%512)-256; } } else { p->type = pt_blob2; p->color = 150 + rand()%6; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()%32)-16); p->vel[j] = (rand()%512)-256; } } } } /* =============== R_RunParticleEffect =============== */ void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) { int i, j; particle_t *p; for (i=0 ; i<count ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; if (count == 1024) { // rocket explosion p->die = cl.time + 5; p->color = ramp1[0]; p->ramp = rand()&3; if (i & 1) { p->type = pt_explode; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()%32)-16); p->vel[j] = (rand()%512)-256; } } else { p->type = pt_explode2; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()%32)-16); p->vel[j] = (rand()%512)-256; } } } else { p->die = cl.time + 0.1*(rand()%5); p->color = (color&~7) + (rand()&7); p->type = pt_slowgrav; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()&15)-8); p->vel[j] = dir[j]*15;// + (rand()%300)-150; } } } } /* =============== R_LavaSplash =============== */ void R_LavaSplash (vec3_t org) { int i, j, k; particle_t *p; float vel; vec3_t dir; for (i=-16 ; i<16 ; i++) for (j=-16 ; j<16 ; j++) for (k=0 ; k<1 ; k++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->die = cl.time + 2 + (rand()&31) * 0.02; p->color = 224 + (rand()&7); p->type = pt_slowgrav; dir[0] = j*8 + (rand()&7); dir[1] = i*8 + (rand()&7); dir[2] = 256; p->org[0] = org[0] + dir[0]; p->org[1] = org[1] + dir[1]; p->org[2] = org[2] + (rand()&63); VectorNormalize (dir); vel = 50 + (rand()&63); VectorScale (dir, vel, p->vel); } } /* =============== R_TeleportSplash =============== */ void R_TeleportSplash (vec3_t org) { int i, j, k; particle_t *p; float vel; vec3_t dir; for (i=-16 ; i<16 ; i+=4) for (j=-16 ; j<16 ; j+=4) for (k=-24 ; k<32 ; k+=4) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->die = cl.time + 0.2 + (rand()&7) * 0.02; p->color = 7 + (rand()&7); p->type = pt_slowgrav; dir[0] = j*8; dir[1] = i*8; dir[2] = k*8; p->org[0] = org[0] + i + (rand()&3); p->org[1] = org[1] + j + (rand()&3); p->org[2] = org[2] + k + (rand()&3); VectorNormalize (dir); vel = 50 + (rand()&63); VectorScale (dir, vel, p->vel); } } /* =============== R_RocketTrail FIXME -- rename function and use #defined types instead of numbers =============== */ void R_RocketTrail (vec3_t start, vec3_t end, int type) { vec3_t vec; float len; int j; particle_t *p; int dec; static int tracercount; VectorSubtract (end, start, vec); len = VectorNormalize (vec); if (type < 128) dec = 3; else { dec = 1; type -= 128; } while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorCopy (vec3_origin, p->vel); p->die = cl.time + 2; switch (type) { case 0: // rocket trail p->ramp = (rand()&3); p->color = ramp3[(int)p->ramp]; p->type = pt_fire; for (j=0 ; j<3 ; j++) p->org[j] = start[j] + ((rand()%6)-3); break; case 1: // smoke smoke p->ramp = (rand()&3) + 2; p->color = ramp3[(int)p->ramp]; p->type = pt_fire; for (j=0 ; j<3 ; j++) p->org[j] = start[j] + ((rand()%6)-3); break; case 2: // blood p->type = pt_grav; p->color = 67 + (rand()&3); for (j=0 ; j<3 ; j++) p->org[j] = start[j] + ((rand()%6)-3); break; case 3: case 5: // tracer p->die = cl.time + 0.5; p->type = pt_static; if (type == 3) p->color = 52 + ((tracercount&4)<<1); else p->color = 230 + ((tracercount&4)<<1); tracercount++; VectorCopy (start, p->org); if (tracercount & 1) { p->vel[0] = 30*vec[1]; p->vel[1] = 30*-vec[0]; } else { p->vel[0] = 30*-vec[1]; p->vel[1] = 30*vec[0]; } break; case 4: // slight blood p->type = pt_grav; p->color = 67 + (rand()&3); for (j=0 ; j<3 ; j++) p->org[j] = start[j] + ((rand()%6)-3); len -= 3; break; case 6: // voor trail p->color = 9*16 + 8 + (rand()&3); p->type = pt_static; p->die = cl.time + 0.3; for (j=0 ; j<3 ; j++) p->org[j] = start[j] + ((rand()&15)-8); break; } VectorAdd (start, vec, start); } } /* =============== CL_RunParticles -- johnfitz -- all the particle behavior, separated from R_DrawParticles =============== */ void CL_RunParticles (void) { particle_t *p, *kill; int i; float time1, time2, time3, dvel, frametime, grav; extern cvar_t sv_gravity; frametime = cl.time - cl.oldtime; time3 = frametime * 15; time2 = frametime * 10; time1 = frametime * 5; grav = frametime * sv_gravity.value * 0.05; dvel = 4*frametime; for ( ;; ) { kill = active_particles; if (kill && kill->die < cl.time) { active_particles = kill->next; kill->next = free_particles; free_particles = kill; continue; } break; } for (p=active_particles ; p ; p=p->next) { for ( ;; ) { kill = p->next; if (kill && kill->die < cl.time) { p->next = kill->next; kill->next = free_particles; free_particles = kill; continue; } break; } p->org[0] += p->vel[0]*frametime; p->org[1] += p->vel[1]*frametime; p->org[2] += p->vel[2]*frametime; switch (p->type) { case pt_static: break; case pt_fire: p->ramp += time1; if (p->ramp >= 6) p->die = -1; else p->color = ramp3[(int)p->ramp]; p->vel[2] += grav; break; case pt_explode: p->ramp += time2; if (p->ramp >=8) p->die = -1; else p->color = ramp1[(int)p->ramp]; for (i=0 ; i<3 ; i++) p->vel[i] += p->vel[i]*dvel; p->vel[2] -= grav; break; case pt_explode2: p->ramp += time3; if (p->ramp >=8) p->die = -1; else p->color = ramp2[(int)p->ramp]; for (i=0 ; i<3 ; i++) p->vel[i] -= p->vel[i]*frametime; p->vel[2] -= grav; break; case pt_blob: for (i=0 ; i<3 ; i++) p->vel[i] += p->vel[i]*dvel; p->vel[2] -= grav; break; case pt_blob2: for (i=0 ; i<2 ; i++) p->vel[i] -= p->vel[i]*dvel; p->vel[2] -= grav; break; case pt_grav: case pt_slowgrav: p->vel[2] -= grav; break; } } } /* =============== R_DrawParticles -- johnfitz -- moved all non-drawing code to CL_RunParticles =============== */ void R_DrawParticles (void) { particle_t *p; float scale; vec3_t up, right, p_up, p_right, p_upright; //johnfitz -- p_ vectors GLubyte color[4], *c; //johnfitz -- particle transparency extern cvar_t r_particles; //johnfitz //float alpha; //johnfitz -- particle transparency if (!r_particles.value) return; //ericw -- avoid empty glBegin(),glEnd() pair below; causes issues on AMD if (!active_particles) return; VectorScale (vup, 1.5, up); VectorScale (vright, 1.5, right); GL_Bind(particletexture); glEnable (GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glDepthMask (GL_FALSE); //johnfitz -- fix for particle z-buffer bug if (r_quadparticles.value) //johnitz -- quads save fillrate { glBegin (GL_QUADS); for (p=active_particles ; p ; p=p->next) { // hack a scale up to keep particles from disapearing scale = (p->org[0] - r_origin[0]) * vpn[0] + (p->org[1] - r_origin[1]) * vpn[1] + (p->org[2] - r_origin[2]) * vpn[2]; if (scale < 20) scale = 1 + 0.08; //johnfitz -- added .08 to be consistent else scale = 1 + scale * 0.004; scale /= 2.0; //quad is half the size of triangle scale *= texturescalefactor; //johnfitz -- compensate for apparent size of different particle textures //johnfitz -- particle transparency and fade out c = (GLubyte *) &d_8to24table[(int)p->color]; color[0] = c[0]; color[1] = c[1]; color[2] = c[2]; //alpha = CLAMP(0, p->die + 0.5 - cl.time, 1); color[3] = 255; //(int)(alpha * 255); glColor4ubv(color); //johnfitz glTexCoord2f (0,0); glVertex3fv (p->org); glTexCoord2f (0.5,0); VectorMA (p->org, scale, up, p_up); glVertex3fv (p_up); glTexCoord2f (0.5,0.5); VectorMA (p_up, scale, right, p_upright); glVertex3fv (p_upright); glTexCoord2f (0,0.5); VectorMA (p->org, scale, right, p_right); glVertex3fv (p_right); rs_particles++; //johnfitz //FIXME: just use r_numparticles } glEnd (); } else //johnitz -- triangles save verts { glBegin (GL_TRIANGLES); for (p=active_particles ; p ; p=p->next) { // hack a scale up to keep particles from disapearing scale = (p->org[0] - r_origin[0]) * vpn[0] + (p->org[1] - r_origin[1]) * vpn[1] + (p->org[2] - r_origin[2]) * vpn[2]; if (scale < 20) scale = 1 + 0.08; //johnfitz -- added .08 to be consistent else scale = 1 + scale * 0.004; scale *= texturescalefactor; //johnfitz -- compensate for apparent size of different particle textures //johnfitz -- particle transparency and fade out c = (GLubyte *) &d_8to24table[(int)p->color]; color[0] = c[0]; color[1] = c[1]; color[2] = c[2]; //alpha = CLAMP(0, p->die + 0.5 - cl.time, 1); color[3] = 255; //(int)(alpha * 255); glColor4ubv(color); //johnfitz glTexCoord2f (0,0); glVertex3fv (p->org); glTexCoord2f (1,0); VectorMA (p->org, scale, up, p_up); glVertex3fv (p_up); glTexCoord2f (0,1); VectorMA (p->org, scale, right, p_right); glVertex3fv (p_right); rs_particles++; //johnfitz //FIXME: just use r_numparticles } glEnd (); } glDepthMask (GL_TRUE); //johnfitz -- fix for particle z-buffer bug glDisable (GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3f(1,1,1); } /* =============== R_DrawParticles_ShowTris -- johnfitz =============== */ void R_DrawParticles_ShowTris (void) { particle_t *p; float scale; vec3_t up, right, p_up, p_right, p_upright; extern cvar_t r_particles; if (!r_particles.value) return; VectorScale (vup, 1.5, up); VectorScale (vright, 1.5, right); if (r_quadparticles.value) { for (p=active_particles ; p ; p=p->next) { glBegin (GL_TRIANGLE_FAN); // hack a scale up to keep particles from disapearing scale = (p->org[0] - r_origin[0]) * vpn[0] + (p->org[1] - r_origin[1]) * vpn[1] + (p->org[2] - r_origin[2]) * vpn[2]; if (scale < 20) scale = 1 + 0.08; //johnfitz -- added .08 to be consistent else scale = 1 + scale * 0.004; scale /= 2.0; //quad is half the size of triangle scale *= texturescalefactor; //compensate for apparent size of different particle textures glVertex3fv (p->org); VectorMA (p->org, scale, up, p_up); glVertex3fv (p_up); VectorMA (p_up, scale, right, p_upright); glVertex3fv (p_upright); VectorMA (p->org, scale, right, p_right); glVertex3fv (p_right); glEnd (); } } else { glBegin (GL_TRIANGLES); for (p=active_particles ; p ; p=p->next) { // hack a scale up to keep particles from disapearing scale = (p->org[0] - r_origin[0]) * vpn[0] + (p->org[1] - r_origin[1]) * vpn[1] + (p->org[2] - r_origin[2]) * vpn[2]; if (scale < 20) scale = 1 + 0.08; //johnfitz -- added .08 to be consistent else scale = 1 + scale * 0.004; scale *= texturescalefactor; //compensate for apparent size of different particle textures glVertex3fv (p->org); VectorMA (p->org, scale, up, p_up); glVertex3fv (p_up); VectorMA (p->org, scale, right, p_right); glVertex3fv (p_right); } glEnd (); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/snd_opus.c������������������������������������������������������������������0000644�0000000�0000000�00000011365�12220541170�015515� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Ogg/Opus streaming music support, loosely based on several open source * Quake engine based projects with many modifications. * * Copyright (C) 2012-2013 O.Sezer <sezero@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT 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 * */ #include "quakedef.h" #if defined(USE_CODEC_OPUS) #include "snd_codec.h" #include "snd_codeci.h" #include "snd_opus.h" #include <errno.h> #include <opusfile.h> /* CALLBACK FUNCTIONS: */ static int opc_fclose (void *f) { return 0; /* we fclose() elsewhere. */ } static int opc_fread (void *f, unsigned char *buf, int size) { int ret; if (size < 0) { errno = EINVAL; return -1; } ret = (int) FS_fread(buf, 1, (size_t)size, (fshandle_t *)f); if (ret == 0 && errno != 0) ret = -1; return ret; } static int opc_fseek (void *f, opus_int64 off, int whence) { if (f == NULL) return (-1); return FS_fseek((fshandle_t *)f, (long) off, whence); } static opus_int64 opc_ftell (void *f) { return (opus_int64) FS_ftell((fshandle_t *)f); } static const OpusFileCallbacks opc_qfs = { (int (*)(void *, unsigned char *, int)) opc_fread, (int (*)(void *, opus_int64, int)) opc_fseek, (opus_int64 (*)(void *)) opc_ftell, (int (*)(void *)) opc_fclose }; static qboolean S_OPUS_CodecInitialize (void) { return true; } static void S_OPUS_CodecShutdown (void) { } static qboolean S_OPUS_CodecOpenStream (snd_stream_t *stream) { OggOpusFile *opFile; const OpusHead *op_info; long numstreams; int res; opFile = op_open_callbacks(&stream->fh, &opc_qfs, NULL, 0, &res); if (!opFile) { Con_Printf("%s is not a valid Opus file (error %i).\n", stream->name, res); goto _fail; } stream->priv = opFile; if (!op_seekable(opFile)) { Con_Printf("Opus stream %s not seekable.\n", stream->name); goto _fail; } op_info = op_head(opFile, -1); if (!op_info) { Con_Printf("Unable to get stream information for %s.\n", stream->name); goto _fail; } /* FIXME: handle section changes */ numstreams = op_info->stream_count; if (numstreams != 1) { Con_Printf("More than one (%ld) stream in %s\n", (long)op_info->stream_count, stream->name); goto _fail; } if (op_info->channel_count != 1 && op_info->channel_count != 2) { Con_Printf("Unsupported number of channels %d in %s\n", op_info->channel_count, stream->name); goto _fail; } /* All Opus audio is coded at 48 kHz, and should also be decoded * at 48 kHz for playback: info->input_sample_rate only tells us * the sampling rate of the original input before opus encoding. * S_RawSamples() shall already downsample this, as necessary. */ stream->info.rate = 48000; stream->info.channels = op_info->channel_count; /* op_read() yields 16-bit output using native endian ordering: */ stream->info.bits = 16; stream->info.width = 2; return true; _fail: if (opFile) op_free(opFile); return false; } static int S_OPUS_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) { int section; /* FIXME: handle section changes */ int cnt, res, rem; opus_int16 * ptr; rem = bytes / stream->info.width; if (rem / stream->info.channels <= 0) return 0; cnt = 0; ptr = (opus_int16 *) buffer; while (1) { /* op_read() yields 16-bit output using native endian ordering. returns * the number of samples read per channel on success, or a negative value * on failure. */ res = op_read((OggOpusFile *)stream->priv, ptr, rem, §ion); if (res <= 0) break; cnt += res; res *= stream->info.channels; rem -= res; if (rem <= 0) break; ptr += res; } if (res < 0) return res; cnt *= (stream->info.channels * stream->info.width); return cnt; } static void S_OPUS_CodecCloseStream (snd_stream_t *stream) { op_free((OggOpusFile *)stream->priv); S_CodecUtilClose(&stream); } static int S_OPUS_CodecRewindStream (snd_stream_t *stream) { return op_pcm_seek ((OggOpusFile *)stream->priv, 0); } snd_codec_t opus_codec = { CODECTYPE_OPUS, true, /* always available. */ "opus", S_OPUS_CodecInitialize, S_OPUS_CodecShutdown, S_OPUS_CodecOpenStream, S_OPUS_CodecReadStream, S_OPUS_CodecRewindStream, S_OPUS_CodecCloseStream, NULL }; #endif /* USE_CODEC_OPUS */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/main_sdl.c������������������������������������������������������������������0000644�0000000�0000000�00000011202�12644413102�015442� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2005 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) #if defined(USE_SDL2) #include <SDL2/SDL.h> #else #include <SDL/SDL.h> #endif #else #include "SDL.h" #endif #include <stdio.h> #if defined(USE_SDL2) /* need at least SDL_2.0.0 */ #define SDL_MIN_X 2 #define SDL_MIN_Y 0 #define SDL_MIN_Z 0 #define SDL_REQUIREDVERSION (SDL_VERSIONNUM(SDL_MIN_X,SDL_MIN_Y,SDL_MIN_Z)) #define SDL_NEW_VERSION_REJECT (SDL_VERSIONNUM(3,0,0)) #else /* need at least SDL_1.2.10 */ #define SDL_MIN_X 1 #define SDL_MIN_Y 2 #define SDL_MIN_Z 10 #define SDL_REQUIREDVERSION (SDL_VERSIONNUM(SDL_MIN_X,SDL_MIN_Y,SDL_MIN_Z)) /* reject 1.3.0 and newer at runtime. */ #define SDL_NEW_VERSION_REJECT (SDL_VERSIONNUM(1,3,0)) #endif static void Sys_AtExit (void) { SDL_Quit(); } static void Sys_InitSDL (void) { #if defined(USE_SDL2) SDL_version v; SDL_version *sdl_version = &v; SDL_GetVersion(&v); #else const SDL_version *sdl_version = SDL_Linked_Version(); #endif Sys_Printf("Found SDL version %i.%i.%i\n",sdl_version->major,sdl_version->minor,sdl_version->patch); if (SDL_VERSIONNUM(sdl_version->major,sdl_version->minor,sdl_version->patch) < SDL_REQUIREDVERSION) { /*reject running under older SDL versions */ Sys_Error("You need at least v%d.%d.%d of SDL to run this game.", SDL_MIN_X,SDL_MIN_Y,SDL_MIN_Z); } if (SDL_VERSIONNUM(sdl_version->major,sdl_version->minor,sdl_version->patch) >= SDL_NEW_VERSION_REJECT) { /*reject running under newer (1.3.x) SDL */ Sys_Error("Your version of SDL library is incompatible with me.\n" "You need a library version in the line of %d.%d.%d\n", SDL_MIN_X,SDL_MIN_Y,SDL_MIN_Z); } if (SDL_Init(0) < 0) { Sys_Error("Couldn't init SDL: %s", SDL_GetError()); } atexit(Sys_AtExit); } #define DEFAULT_MEMORY (256 * 1024 * 1024) // ericw -- was 72MB (64-bit) / 64MB (32-bit) static quakeparms_t parms; // On OS X we call SDL_main from the launcher, but SDL2 doesn't redefine main // as SDL_main on OS X anymore, so we do it ourselves. #if defined(USE_SDL2) && defined(__APPLE__) #define main SDL_main #endif int main(int argc, char *argv[]) { int t; double time, oldtime, newtime; host_parms = &parms; parms.basedir = "."; parms.argc = argc; parms.argv = argv; COM_InitArgv(parms.argc, parms.argv); isDedicated = (COM_CheckParm("-dedicated") != 0); Sys_InitSDL (); Sys_Init(); parms.memsize = DEFAULT_MEMORY; if (COM_CheckParm("-heapsize")) { t = COM_CheckParm("-heapsize") + 1; if (t < com_argc) parms.memsize = Q_atoi(com_argv[t]) * 1024; } parms.membase = malloc (parms.memsize); if (!parms.membase) Sys_Error ("Not enough memory free; check disk space\n"); Sys_Printf("Quake %1.2f (c) id Software\n", VERSION); Sys_Printf("GLQuake %1.2f (c) id Software\n", GLQUAKE_VERSION); Sys_Printf("FitzQuake %1.2f (c) John Fitzgibbons\n", FITZQUAKE_VERSION); Sys_Printf("FitzQuake SDL port (c) SleepwalkR, Baker\n"); Sys_Printf("QuakeSpasm %1.2f.%d (c) Ozkan Sezer, Eric Wasylishen & others\n", QUAKESPASM_VERSION, QUAKESPASM_VER_PATCH); Sys_Printf("Host_Init\n"); Host_Init(); oldtime = Sys_DoubleTime(); if (isDedicated) { while (1) { newtime = Sys_DoubleTime (); time = newtime - oldtime; while (time < sys_ticrate.value ) { SDL_Delay(1); newtime = Sys_DoubleTime (); time = newtime - oldtime; } Host_Frame (time); oldtime = newtime; } } else while (1) { /* If we have no input focus at all, sleep a bit */ if (!VID_HasMouseOrInputFocus() || cl.paused) { SDL_Delay(16); } /* If we're minimised, sleep a bit more */ if (VID_IsMinimized()) { scr_skipupdate = 1; SDL_Delay(32); } else { scr_skipupdate = 0; } newtime = Sys_DoubleTime (); time = newtime - oldtime; Host_Frame (time); if (time < sys_throttle.value) SDL_Delay(1); oldtime = newtime; } return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/menu.c����������������������������������������������������������������������0000644�0000000�0000000�00000153243�12627274007�014646� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #include "bgmusic.h" void (*vid_menucmdfn)(void); //johnfitz void (*vid_menudrawfn)(void); void (*vid_menukeyfn)(int key); enum m_state_e m_state; void M_Menu_Main_f (void); void M_Menu_SinglePlayer_f (void); void M_Menu_Load_f (void); void M_Menu_Save_f (void); void M_Menu_MultiPlayer_f (void); void M_Menu_Setup_f (void); void M_Menu_Net_f (void); void M_Menu_LanConfig_f (void); void M_Menu_GameOptions_f (void); void M_Menu_Search_f (void); void M_Menu_ServerList_f (void); void M_Menu_Options_f (void); void M_Menu_Keys_f (void); void M_Menu_Video_f (void); void M_Menu_Help_f (void); void M_Menu_Quit_f (void); void M_Main_Draw (void); void M_SinglePlayer_Draw (void); void M_Load_Draw (void); void M_Save_Draw (void); void M_MultiPlayer_Draw (void); void M_Setup_Draw (void); void M_Net_Draw (void); void M_LanConfig_Draw (void); void M_GameOptions_Draw (void); void M_Search_Draw (void); void M_ServerList_Draw (void); void M_Options_Draw (void); void M_Keys_Draw (void); void M_Video_Draw (void); void M_Help_Draw (void); void M_Quit_Draw (void); void M_Main_Key (int key); void M_SinglePlayer_Key (int key); void M_Load_Key (int key); void M_Save_Key (int key); void M_MultiPlayer_Key (int key); void M_Setup_Key (int key); void M_Net_Key (int key); void M_LanConfig_Key (int key); void M_GameOptions_Key (int key); void M_Search_Key (int key); void M_ServerList_Key (int key); void M_Options_Key (int key); void M_Keys_Key (int key); void M_Video_Key (int key); void M_Help_Key (int key); void M_Quit_Key (int key); qboolean m_entersound; // play after drawing a frame, so caching // won't disrupt the sound qboolean m_recursiveDraw; enum m_state_e m_return_state; qboolean m_return_onerror; char m_return_reason [32]; #define StartingGame (m_multiplayer_cursor == 1) #define JoiningGame (m_multiplayer_cursor == 0) #define IPXConfig (m_net_cursor == 0) #define TCPIPConfig (m_net_cursor == 1) void M_ConfigureNetSubsystem(void); /* ================ M_DrawCharacter Draws one solid graphics character ================ */ void M_DrawCharacter (int cx, int line, int num) { Draw_Character (cx, line, num); } void M_Print (int cx, int cy, const char *str) { while (*str) { M_DrawCharacter (cx, cy, (*str)+128); str++; cx += 8; } } void M_PrintWhite (int cx, int cy, const char *str) { while (*str) { M_DrawCharacter (cx, cy, *str); str++; cx += 8; } } void M_DrawTransPic (int x, int y, qpic_t *pic) { Draw_Pic (x, y, pic); //johnfitz -- simplified becuase centering is handled elsewhere } void M_DrawPic (int x, int y, qpic_t *pic) { Draw_Pic (x, y, pic); //johnfitz -- simplified becuase centering is handled elsewhere } void M_DrawTransPicTranslate (int x, int y, qpic_t *pic, int top, int bottom) //johnfitz -- more parameters { Draw_TransPicTranslate (x, y, pic, top, bottom); //johnfitz -- simplified becuase centering is handled elsewhere } void M_DrawTextBox (int x, int y, int width, int lines) { qpic_t *p; int cx, cy; int n; // draw left side cx = x; cy = y; p = Draw_CachePic ("gfx/box_tl.lmp"); M_DrawTransPic (cx, cy, p); p = Draw_CachePic ("gfx/box_ml.lmp"); for (n = 0; n < lines; n++) { cy += 8; M_DrawTransPic (cx, cy, p); } p = Draw_CachePic ("gfx/box_bl.lmp"); M_DrawTransPic (cx, cy+8, p); // draw middle cx += 8; while (width > 0) { cy = y; p = Draw_CachePic ("gfx/box_tm.lmp"); M_DrawTransPic (cx, cy, p); p = Draw_CachePic ("gfx/box_mm.lmp"); for (n = 0; n < lines; n++) { cy += 8; if (n == 1) p = Draw_CachePic ("gfx/box_mm2.lmp"); M_DrawTransPic (cx, cy, p); } p = Draw_CachePic ("gfx/box_bm.lmp"); M_DrawTransPic (cx, cy+8, p); width -= 2; cx += 16; } // draw right side cy = y; p = Draw_CachePic ("gfx/box_tr.lmp"); M_DrawTransPic (cx, cy, p); p = Draw_CachePic ("gfx/box_mr.lmp"); for (n = 0; n < lines; n++) { cy += 8; M_DrawTransPic (cx, cy, p); } p = Draw_CachePic ("gfx/box_br.lmp"); M_DrawTransPic (cx, cy+8, p); } //============================================================================= int m_save_demonum; /* ================ M_ToggleMenu_f ================ */ void M_ToggleMenu_f (void) { m_entersound = true; if (key_dest == key_menu) { if (m_state != m_main) { M_Menu_Main_f (); return; } IN_Activate(); key_dest = key_game; m_state = m_none; return; } if (key_dest == key_console) { Con_ToggleConsole_f (); } else { M_Menu_Main_f (); } } //============================================================================= /* MAIN MENU */ int m_main_cursor; #define MAIN_ITEMS 5 void M_Menu_Main_f (void) { if (key_dest != key_menu) { m_save_demonum = cls.demonum; cls.demonum = -1; } IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_main; m_entersound = true; } void M_Main_Draw (void) { int f; qpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/ttl_main.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") ); f = (int)(realtime * 10)%6; M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); } void M_Main_Key (int key) { switch (key) { case K_ESCAPE: IN_Activate(); key_dest = key_game; m_state = m_none; cls.demonum = m_save_demonum; if (!fitzmode) /* QuakeSpasm customization: */ break; if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected) CL_NextDemo (); break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); if (++m_main_cursor >= MAIN_ITEMS) m_main_cursor = 0; break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); if (--m_main_cursor < 0) m_main_cursor = MAIN_ITEMS - 1; break; case K_ENTER: case K_KP_ENTER: m_entersound = true; switch (m_main_cursor) { case 0: M_Menu_SinglePlayer_f (); break; case 1: M_Menu_MultiPlayer_f (); break; case 2: M_Menu_Options_f (); break; case 3: M_Menu_Help_f (); break; case 4: M_Menu_Quit_f (); break; } } } //============================================================================= /* SINGLE PLAYER MENU */ int m_singleplayer_cursor; #define SINGLEPLAYER_ITEMS 3 void M_Menu_SinglePlayer_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_singleplayer; m_entersound = true; } void M_SinglePlayer_Draw (void) { int f; qpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/ttl_sgl.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") ); f = (int)(realtime * 10)%6; M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); } void M_SinglePlayer_Key (int key) { switch (key) { case K_ESCAPE: M_Menu_Main_f (); break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS) m_singleplayer_cursor = 0; break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); if (--m_singleplayer_cursor < 0) m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1; break; case K_ENTER: case K_KP_ENTER: m_entersound = true; switch (m_singleplayer_cursor) { case 0: if (sv.active) if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n", 0.0f)) break; IN_Activate(); key_dest = key_game; if (sv.active) Cbuf_AddText ("disconnect\n"); Cbuf_AddText ("maxplayers 1\n"); Cbuf_AddText ("deathmatch 0\n"); //johnfitz Cbuf_AddText ("coop 0\n"); //johnfitz Cbuf_AddText ("map start\n"); break; case 1: M_Menu_Load_f (); break; case 2: M_Menu_Save_f (); break; } } } //============================================================================= /* LOAD/SAVE MENU */ int load_cursor; // 0 < load_cursor < MAX_SAVEGAMES #define MAX_SAVEGAMES 20 /* johnfitz -- increased from 12 */ char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1]; int loadable[MAX_SAVEGAMES]; void M_ScanSaves (void) { int i, j; char name[MAX_OSPATH]; FILE *f; int version; for (i = 0; i < MAX_SAVEGAMES; i++) { strcpy (m_filenames[i], "--- UNUSED SLOT ---"); loadable[i] = false; q_snprintf (name, sizeof(name), "%s/s%i.sav", com_gamedir, i); f = fopen (name, "r"); if (!f) continue; fscanf (f, "%i\n", &version); fscanf (f, "%79s\n", name); strncpy (m_filenames[i], name, sizeof(m_filenames[i])-1); // change _ back to space for (j = 0; j < SAVEGAME_COMMENT_LENGTH; j++) { if (m_filenames[i][j] == '_') m_filenames[i][j] = ' '; } loadable[i] = true; fclose (f); } } void M_Menu_Load_f (void) { m_entersound = true; m_state = m_load; IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; M_ScanSaves (); } void M_Menu_Save_f (void) { if (!sv.active) return; if (cl.intermission) return; if (svs.maxclients != 1) return; m_entersound = true; m_state = m_save; IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; M_ScanSaves (); } void M_Load_Draw (void) { int i; qpic_t *p; p = Draw_CachePic ("gfx/p_load.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); for (i = 0; i < MAX_SAVEGAMES; i++) M_Print (16, 32 + 8*i, m_filenames[i]); // line cursor M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1)); } void M_Save_Draw (void) { int i; qpic_t *p; p = Draw_CachePic ("gfx/p_save.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); for (i = 0; i < MAX_SAVEGAMES; i++) M_Print (16, 32 + 8*i, m_filenames[i]); // line cursor M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1)); } void M_Load_Key (int k) { switch (k) { case K_ESCAPE: M_Menu_SinglePlayer_f (); break; case K_ENTER: case K_KP_ENTER: S_LocalSound ("misc/menu2.wav"); if (!loadable[load_cursor]) return; m_state = m_none; IN_Activate(); key_dest = key_game; // Host_Loadgame_f can't bring up the loading plaque because too much // stack space has been used, so do it now SCR_BeginLoadingPlaque (); // issue the load command Cbuf_AddText (va ("load s%i\n", load_cursor) ); return; case K_UPARROW: case K_LEFTARROW: S_LocalSound ("misc/menu1.wav"); load_cursor--; if (load_cursor < 0) load_cursor = MAX_SAVEGAMES-1; break; case K_DOWNARROW: case K_RIGHTARROW: S_LocalSound ("misc/menu1.wav"); load_cursor++; if (load_cursor >= MAX_SAVEGAMES) load_cursor = 0; break; } } void M_Save_Key (int k) { switch (k) { case K_ESCAPE: M_Menu_SinglePlayer_f (); break; case K_ENTER: case K_KP_ENTER: m_state = m_none; IN_Activate(); key_dest = key_game; Cbuf_AddText (va("save s%i\n", load_cursor)); return; case K_UPARROW: case K_LEFTARROW: S_LocalSound ("misc/menu1.wav"); load_cursor--; if (load_cursor < 0) load_cursor = MAX_SAVEGAMES-1; break; case K_DOWNARROW: case K_RIGHTARROW: S_LocalSound ("misc/menu1.wav"); load_cursor++; if (load_cursor >= MAX_SAVEGAMES) load_cursor = 0; break; } } //============================================================================= /* MULTIPLAYER MENU */ int m_multiplayer_cursor; #define MULTIPLAYER_ITEMS 3 void M_Menu_MultiPlayer_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_multiplayer; m_entersound = true; } void M_MultiPlayer_Draw (void) { int f; qpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mp_menu.lmp") ); f = (int)(realtime * 10)%6; M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); if (ipxAvailable || tcpipAvailable) return; M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available"); } void M_MultiPlayer_Key (int key) { switch (key) { case K_ESCAPE: M_Menu_Main_f (); break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS) m_multiplayer_cursor = 0; break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); if (--m_multiplayer_cursor < 0) m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1; break; case K_ENTER: case K_KP_ENTER: m_entersound = true; switch (m_multiplayer_cursor) { case 0: if (ipxAvailable || tcpipAvailable) M_Menu_Net_f (); break; case 1: if (ipxAvailable || tcpipAvailable) M_Menu_Net_f (); break; case 2: M_Menu_Setup_f (); break; } } } //============================================================================= /* SETUP MENU */ int setup_cursor = 4; int setup_cursor_table[] = {40, 56, 80, 104, 140}; char setup_hostname[16]; char setup_myname[16]; int setup_oldtop; int setup_oldbottom; int setup_top; int setup_bottom; #define NUM_SETUP_CMDS 5 void M_Menu_Setup_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_setup; m_entersound = true; Q_strcpy(setup_myname, cl_name.string); Q_strcpy(setup_hostname, hostname.string); setup_top = setup_oldtop = ((int)cl_color.value) >> 4; setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15; } void M_Setup_Draw (void) { qpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_Print (64, 40, "Hostname"); M_DrawTextBox (160, 32, 16, 1); M_Print (168, 40, setup_hostname); M_Print (64, 56, "Your name"); M_DrawTextBox (160, 48, 16, 1); M_Print (168, 56, setup_myname); M_Print (64, 80, "Shirt color"); M_Print (64, 104, "Pants color"); M_DrawTextBox (64, 140-8, 14, 1); M_Print (72, 140, "Accept Changes"); p = Draw_CachePic ("gfx/bigbox.lmp"); M_DrawTransPic (160, 64, p); p = Draw_CachePic ("gfx/menuplyr.lmp"); M_DrawTransPicTranslate (172, 72, p, setup_top, setup_bottom); M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1)); if (setup_cursor == 0) M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1)); if (setup_cursor == 1) M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1)); } void M_Setup_Key (int k) { switch (k) { case K_ESCAPE: M_Menu_MultiPlayer_f (); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); setup_cursor--; if (setup_cursor < 0) setup_cursor = NUM_SETUP_CMDS-1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); setup_cursor++; if (setup_cursor >= NUM_SETUP_CMDS) setup_cursor = 0; break; case K_LEFTARROW: if (setup_cursor < 2) return; S_LocalSound ("misc/menu3.wav"); if (setup_cursor == 2) setup_top = setup_top - 1; if (setup_cursor == 3) setup_bottom = setup_bottom - 1; break; case K_RIGHTARROW: if (setup_cursor < 2) return; forward: S_LocalSound ("misc/menu3.wav"); if (setup_cursor == 2) setup_top = setup_top + 1; if (setup_cursor == 3) setup_bottom = setup_bottom + 1; break; case K_ENTER: case K_KP_ENTER: if (setup_cursor == 0 || setup_cursor == 1) return; if (setup_cursor == 2 || setup_cursor == 3) goto forward; // setup_cursor == 4 (OK) if (Q_strcmp(cl_name.string, setup_myname) != 0) Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) ); if (Q_strcmp(hostname.string, setup_hostname) != 0) Cvar_Set("hostname", setup_hostname); if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom) Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) ); m_entersound = true; M_Menu_MultiPlayer_f (); break; case K_BACKSPACE: if (setup_cursor == 0) { if (strlen(setup_hostname)) setup_hostname[strlen(setup_hostname)-1] = 0; } if (setup_cursor == 1) { if (strlen(setup_myname)) setup_myname[strlen(setup_myname)-1] = 0; } break; } if (setup_top > 13) setup_top = 0; if (setup_top < 0) setup_top = 13; if (setup_bottom > 13) setup_bottom = 0; if (setup_bottom < 0) setup_bottom = 13; } void M_Setup_Char (int k) { int l; switch (setup_cursor) { case 0: l = strlen(setup_hostname); if (l < 15) { setup_hostname[l+1] = 0; setup_hostname[l] = k; } break; case 1: l = strlen(setup_myname); if (l < 15) { setup_myname[l+1] = 0; setup_myname[l] = k; } break; } } qboolean M_Setup_TextEntry (void) { return (setup_cursor == 0 || setup_cursor == 1); } //============================================================================= /* NET MENU */ int m_net_cursor; int m_net_items; const char *net_helpMessage [] = { /* .........1.........2.... */ " Novell network LANs ", " or Windows 95 DOS-box. ", " ", "(LAN=Local Area Network)", " Commonly used to play ", " over the Internet, but ", " also used on a Local ", " Area Network. " }; void M_Menu_Net_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_net; m_entersound = true; m_net_items = 2; if (m_net_cursor >= m_net_items) m_net_cursor = 0; m_net_cursor--; M_Net_Key (K_DOWNARROW); } void M_Net_Draw (void) { int f; qpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); f = 32; if (ipxAvailable) p = Draw_CachePic ("gfx/netmen3.lmp"); else p = Draw_CachePic ("gfx/dim_ipx.lmp"); M_DrawTransPic (72, f, p); f += 19; if (tcpipAvailable) p = Draw_CachePic ("gfx/netmen4.lmp"); else p = Draw_CachePic ("gfx/dim_tcp.lmp"); M_DrawTransPic (72, f, p); f = (320-26*8)/2; M_DrawTextBox (f, 96, 24, 4); f += 8; M_Print (f, 104, net_helpMessage[m_net_cursor*4+0]); M_Print (f, 112, net_helpMessage[m_net_cursor*4+1]); M_Print (f, 120, net_helpMessage[m_net_cursor*4+2]); M_Print (f, 128, net_helpMessage[m_net_cursor*4+3]); f = (int)(realtime * 10)%6; M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); } void M_Net_Key (int k) { again: switch (k) { case K_ESCAPE: M_Menu_MultiPlayer_f (); break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); if (++m_net_cursor >= m_net_items) m_net_cursor = 0; break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); if (--m_net_cursor < 0) m_net_cursor = m_net_items - 1; break; case K_ENTER: case K_KP_ENTER: m_entersound = true; M_Menu_LanConfig_f (); break; } if (m_net_cursor == 0 && !ipxAvailable) goto again; if (m_net_cursor == 1 && !tcpipAvailable) goto again; } //============================================================================= /* OPTIONS MENU */ enum { OPT_CUSTOMIZE = 0, OPT_CONSOLE, // 1 OPT_DEFAULTS, // 2 OPT_SCALE, OPT_SCRSIZE, OPT_GAMMA, OPT_MOUSESPEED, OPT_SBALPHA, OPT_SNDVOL, OPT_MUSICVOL, OPT_MUSICEXT, OPT_ALWAYRUN, OPT_INVMOUSE, OPT_ALWAYSMLOOK, OPT_LOOKSPRING, OPT_LOOKSTRAFE, //#ifdef _WIN32 // OPT_USEMOUSE, //#endif OPT_VIDEO, // This is the last before OPTIONS_ITEMS OPTIONS_ITEMS }; #define SLIDER_RANGE 10 int options_cursor; void M_Menu_Options_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_options; m_entersound = true; } void M_AdjustSliders (int dir) { float f, l; S_LocalSound ("misc/menu3.wav"); switch (options_cursor) { case OPT_SCALE: // console and menu scale l = ((vid.width + 31) / 32) / 10.0; f = scr_conscale.value + dir * .1; if (f < 1) f = 1; else if(f > l) f = l; Cvar_SetValue ("scr_conscale", f); Cvar_SetValue ("scr_menuscale", f); Cvar_SetValue ("scr_sbarscale", f); break; case OPT_SCRSIZE: // screen size f = scr_viewsize.value + dir * 10; if (f > 120) f = 120; else if(f < 30) f = 30; Cvar_SetValue ("viewsize", f); break; case OPT_GAMMA: // gamma f = vid_gamma.value - dir * 0.05; if (f < 0.5) f = 0.5; else if (f > 1) f = 1; Cvar_SetValue ("gamma", f); break; case OPT_MOUSESPEED: // mouse speed f = sensitivity.value + dir * 0.5; if (f > 11) f = 11; else if (f < 1) f = 1; Cvar_SetValue ("sensitivity", f); break; case OPT_SBALPHA: // statusbar alpha f = scr_sbaralpha.value - dir * 0.05; if (f < 0) f = 0; else if (f > 1) f = 1; Cvar_SetValue ("scr_sbaralpha", f); break; case OPT_MUSICVOL: // music volume f = bgmvolume.value + dir * 0.1; if (f < 0) f = 0; else if (f > 1) f = 1; Cvar_SetValue ("bgmvolume", f); break; case OPT_MUSICEXT: // enable external music vs cdaudio Cvar_Set ("bgm_extmusic", bgm_extmusic.value ? "0" : "1"); break; case OPT_SNDVOL: // sfx volume f = sfxvolume.value + dir * 0.1; if (f < 0) f = 0; else if (f > 1) f = 1; Cvar_SetValue ("volume", f); break; case OPT_ALWAYRUN: // always run if (cl_movespeedkey.value <= 1) Cvar_Set ("cl_movespeedkey", "2.0"); if (cl_forwardspeed.value > 200) { Cvar_Set ("cl_forwardspeed", "200"); Cvar_Set ("cl_backspeed", "200"); } else { Cvar_SetValue ("cl_forwardspeed", 200 * cl_movespeedkey.value); Cvar_SetValue ("cl_backspeed", 200 * cl_movespeedkey.value); } break; case OPT_INVMOUSE: // invert mouse Cvar_SetValue ("m_pitch", -m_pitch.value); break; case OPT_ALWAYSMLOOK: if (in_mlook.state & 1) Cbuf_AddText("-mlook"); else Cbuf_AddText("+mlook"); break; case OPT_LOOKSPRING: // lookspring Cvar_Set ("lookspring", lookspring.value ? "0" : "1"); break; case OPT_LOOKSTRAFE: // lookstrafe Cvar_Set ("lookstrafe", lookstrafe.value ? "0" : "1"); break; } } void M_DrawSlider (int x, int y, float range) { int i; if (range < 0) range = 0; if (range > 1) range = 1; M_DrawCharacter (x-8, y, 128); for (i = 0; i < SLIDER_RANGE; i++) M_DrawCharacter (x + i*8, y, 129); M_DrawCharacter (x+i*8, y, 130); M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131); } void M_DrawCheckbox (int x, int y, int on) { #if 0 if (on) M_DrawCharacter (x, y, 131); else M_DrawCharacter (x, y, 129); #endif if (on) M_Print (x, y, "on"); else M_Print (x, y, "off"); } void M_Options_Draw (void) { float r, l; qpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_option.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); // Draw the items in the order of the enum defined above: // OPT_CUSTOMIZE: M_Print (16, 32, " Controls"); // OPT_CONSOLE: M_Print (16, 32 + 8*OPT_CONSOLE, " Goto console"); // OPT_DEFAULTS: M_Print (16, 32 + 8*OPT_DEFAULTS, " Reset config"); // OPT_SCALE: M_Print (16, 32 + 8*OPT_SCALE, " Scale"); l = (vid.width / 320.0) - 1; r = l > 0 ? (scr_conscale.value - 1) / l : 0; M_DrawSlider (220, 32 + 8*OPT_SCALE, r); // OPT_SCRSIZE: M_Print (16, 32 + 8*OPT_SCRSIZE, " Screen size"); r = (scr_viewsize.value - 30) / (120 - 30); M_DrawSlider (220, 32 + 8*OPT_SCRSIZE, r); // OPT_GAMMA: M_Print (16, 32 + 8*OPT_GAMMA, " Brightness"); r = (1.0 - vid_gamma.value) / 0.5; M_DrawSlider (220, 32 + 8*OPT_GAMMA, r); // OPT_MOUSESPEED: M_Print (16, 32 + 8*OPT_MOUSESPEED, " Mouse Speed"); r = (sensitivity.value - 1)/10; M_DrawSlider (220, 32 + 8*OPT_MOUSESPEED, r); // OPT_SBALPHA: M_Print (16, 32 + 8*OPT_SBALPHA, " Statusbar alpha"); r = (1.0 - scr_sbaralpha.value) ; // scr_sbaralpha range is 1.0 to 0.0 M_DrawSlider (220, 32 + 8*OPT_SBALPHA, r); // OPT_SNDVOL: M_Print (16, 32 + 8*OPT_SNDVOL, " Sound Volume"); r = sfxvolume.value; M_DrawSlider (220, 32 + 8*OPT_SNDVOL, r); // OPT_MUSICVOL: M_Print (16, 32 + 8*OPT_MUSICVOL, " Music Volume"); r = bgmvolume.value; M_DrawSlider (220, 32 + 8*OPT_MUSICVOL, r); // OPT_MUSICEXT: M_Print (16, 32 + 8*OPT_MUSICEXT, " External Music"); M_DrawCheckbox (220, 32 + 8*OPT_MUSICEXT, bgm_extmusic.value); // OPT_ALWAYRUN: M_Print (16, 32 + 8*OPT_ALWAYRUN, " Always Run"); M_DrawCheckbox (220, 32 + 8*OPT_ALWAYRUN, cl_forwardspeed.value > 200); // OPT_INVMOUSE: M_Print (16, 32 + 8*OPT_INVMOUSE, " Invert Mouse"); M_DrawCheckbox (220, 32 + 8*OPT_INVMOUSE, m_pitch.value < 0); // OPT_ALWAYSMLOOK: M_Print (16, 32 + 8*OPT_ALWAYSMLOOK, " Mouse Look"); M_DrawCheckbox (220, 32 + 8*OPT_ALWAYSMLOOK, in_mlook.state & 1); // OPT_LOOKSPRING: M_Print (16, 32 + 8*OPT_LOOKSPRING, " Lookspring"); M_DrawCheckbox (220, 32 + 8*OPT_LOOKSPRING, lookspring.value); // OPT_LOOKSTRAFE: M_Print (16, 32 + 8*OPT_LOOKSTRAFE, " Lookstrafe"); M_DrawCheckbox (220, 32 + 8*OPT_LOOKSTRAFE, lookstrafe.value); // OPT_VIDEO: if (vid_menudrawfn) M_Print (16, 32 + 8*OPT_VIDEO, " Video Options"); // cursor M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1)); } void M_Options_Key (int k) { switch (k) { case K_ESCAPE: M_Menu_Main_f (); break; case K_ENTER: case K_KP_ENTER: m_entersound = true; switch (options_cursor) { case OPT_CUSTOMIZE: M_Menu_Keys_f (); break; case OPT_CONSOLE: m_state = m_none; Con_ToggleConsole_f (); break; case OPT_DEFAULTS: if (SCR_ModalMessage("This will reset all controls\n" "and stored cvars. Continue? (y/n)\n", 15.0f)) { Cbuf_AddText ("resetcfg\n"); Cbuf_AddText ("exec default.cfg\n"); } break; case OPT_VIDEO: M_Menu_Video_f (); break; default: M_AdjustSliders (1); break; } return; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); options_cursor--; if (options_cursor < 0) options_cursor = OPTIONS_ITEMS-1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); options_cursor++; if (options_cursor >= OPTIONS_ITEMS) options_cursor = 0; break; case K_LEFTARROW: M_AdjustSliders (-1); break; case K_RIGHTARROW: M_AdjustSliders (1); break; } if (options_cursor == OPTIONS_ITEMS - 1 && vid_menudrawfn == NULL) { if (k == K_UPARROW) options_cursor = OPTIONS_ITEMS - 2; else options_cursor = 0; } } //============================================================================= /* KEYS MENU */ const char *bindnames[][2] = { {"+attack", "attack"}, {"impulse 10", "next weapon"}, {"impulse 12", "prev weapon"}, {"+jump", "jump / swim up"}, {"+forward", "walk forward"}, {"+back", "backpedal"}, {"+left", "turn left"}, {"+right", "turn right"}, {"+speed", "run"}, {"+moveleft", "step left"}, {"+moveright", "step right"}, {"+strafe", "sidestep"}, {"+lookup", "look up"}, {"+lookdown", "look down"}, {"centerview", "center view"}, {"+mlook", "mouse look"}, {"+klook", "keyboard look"}, {"+moveup", "swim up"}, {"+movedown", "swim down"} }; #define NUMCOMMANDS (sizeof(bindnames)/sizeof(bindnames[0])) static int keys_cursor; static qboolean bind_grab; void M_Menu_Keys_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_keys; m_entersound = true; } void M_FindKeysForCommand (const char *command, int *twokeys) { int count; int j; int l; char *b; twokeys[0] = twokeys[1] = -1; l = strlen(command); count = 0; for (j = 0; j < 256; j++) { b = keybindings[j]; if (!b) continue; if (!strncmp (b, command, l) ) { twokeys[count] = j; count++; if (count == 2) break; } } } void M_UnbindCommand (const char *command) { int j; int l; char *b; l = strlen(command); for (j = 0; j < 256; j++) { b = keybindings[j]; if (!b) continue; if (!strncmp (b, command, l) ) Key_SetBinding (j, NULL); } } extern qpic_t *pic_up, *pic_down; void M_Keys_Draw (void) { int i, x, y; int keys[2]; const char *name; qpic_t *p; p = Draw_CachePic ("gfx/ttl_cstm.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); if (bind_grab) M_Print (12, 32, "Press a key or button for this action"); else M_Print (18, 32, "Enter to change, backspace to clear"); // search for known bindings for (i = 0; i < (int)NUMCOMMANDS; i++) { y = 48 + 8*i; M_Print (16, y, bindnames[i][1]); M_FindKeysForCommand (bindnames[i][0], keys); if (keys[0] == -1) { M_Print (140, y, "???"); } else { name = Key_KeynumToString (keys[0]); M_Print (140, y, name); x = strlen(name) * 8; if (keys[1] != -1) { M_Print (140 + x + 8, y, "or"); M_Print (140 + x + 32, y, Key_KeynumToString (keys[1])); } } } if (bind_grab) M_DrawCharacter (130, 48 + keys_cursor*8, '='); else M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1)); } void M_Keys_Key (int k) { char cmd[80]; int keys[2]; if (bind_grab) { // defining a key S_LocalSound ("misc/menu1.wav"); if ((k != K_ESCAPE) && (k != '`')) { sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]); Cbuf_InsertText (cmd); } bind_grab = false; IN_Deactivate(modestate == MS_WINDOWED); // deactivate because we're returning to the menu return; } switch (k) { case K_ESCAPE: M_Menu_Options_f (); break; case K_LEFTARROW: case K_UPARROW: S_LocalSound ("misc/menu1.wav"); keys_cursor--; if (keys_cursor < 0) keys_cursor = NUMCOMMANDS-1; break; case K_DOWNARROW: case K_RIGHTARROW: S_LocalSound ("misc/menu1.wav"); keys_cursor++; if (keys_cursor >= (int)NUMCOMMANDS) keys_cursor = 0; break; case K_ENTER: // go into bind mode case K_KP_ENTER: M_FindKeysForCommand (bindnames[keys_cursor][0], keys); S_LocalSound ("misc/menu2.wav"); if (keys[1] != -1) M_UnbindCommand (bindnames[keys_cursor][0]); bind_grab = true; IN_Activate(); // activate to allow mouse key binding break; case K_BACKSPACE: // delete bindings case K_DEL: S_LocalSound ("misc/menu2.wav"); M_UnbindCommand (bindnames[keys_cursor][0]); break; } } //============================================================================= /* VIDEO MENU */ void M_Menu_Video_f (void) { (*vid_menucmdfn) (); //johnfitz } void M_Video_Draw (void) { (*vid_menudrawfn) (); } void M_Video_Key (int key) { (*vid_menukeyfn) (key); } //============================================================================= /* HELP MENU */ int help_page; #define NUM_HELP_PAGES 6 void M_Menu_Help_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_help; m_entersound = true; help_page = 0; } void M_Help_Draw (void) { M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) ); } void M_Help_Key (int key) { switch (key) { case K_ESCAPE: M_Menu_Main_f (); break; case K_UPARROW: case K_RIGHTARROW: m_entersound = true; if (++help_page >= NUM_HELP_PAGES) help_page = 0; break; case K_DOWNARROW: case K_LEFTARROW: m_entersound = true; if (--help_page < 0) help_page = NUM_HELP_PAGES-1; break; } } //============================================================================= /* QUIT MENU */ int msgNumber; enum m_state_e m_quit_prevstate; qboolean wasInMenus; void M_Menu_Quit_f (void) { if (m_state == m_quit) return; wasInMenus = (key_dest == key_menu); IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_quit_prevstate = m_state; m_state = m_quit; m_entersound = true; msgNumber = rand()&7; } void M_Quit_Key (int key) { if (key == K_ESCAPE) { if (wasInMenus) { m_state = m_quit_prevstate; m_entersound = true; } else { IN_Activate(); key_dest = key_game; m_state = m_none; } } } void M_Quit_Char (int key) { switch (key) { case 'n': case 'N': if (wasInMenus) { m_state = m_quit_prevstate; m_entersound = true; } else { IN_Activate(); key_dest = key_game; m_state = m_none; } break; case 'y': case 'Y': IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_console; Host_Quit_f (); break; default: break; } } qboolean M_Quit_TextEntry (void) { return true; } void M_Quit_Draw (void) //johnfitz -- modified for new quit message { char msg1[40]; char msg2[] = "by Ozkan, Ericw & Stevenaaus"; /* msg2/msg3 are mostly [40] */ char msg3[] = "Press y to quit"; int boxlen; if (wasInMenus) { m_state = m_quit_prevstate; m_recursiveDraw = true; M_Draw (); m_state = m_quit; } sprintf(msg1, "QuakeSpasm %1.2f.%d", (float)QUAKESPASM_VERSION, QUAKESPASM_VER_PATCH); //okay, this is kind of fucked up. M_DrawTextBox will always act as if //width is even. Also, the width and lines values are for the interior of the box, //but the x and y values include the border. boxlen = q_max(strlen(msg1), q_max((sizeof(msg2)-1),(sizeof(msg3)-1))) + 1; if (boxlen & 1) boxlen++; M_DrawTextBox (160-4*(boxlen+2), 76, boxlen, 4); //now do the text M_Print (160-4*strlen(msg1), 88, msg1); M_Print (160-4*(sizeof(msg2)-1), 96, msg2); M_PrintWhite (160-4*(sizeof(msg3)-1), 104, msg3); } //============================================================================= /* LAN CONFIG MENU */ int lanConfig_cursor = -1; int lanConfig_cursor_table [] = {72, 92, 124}; #define NUM_LANCONFIG_CMDS 3 int lanConfig_port; char lanConfig_portname[6]; char lanConfig_joinname[22]; void M_Menu_LanConfig_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_lanconfig; m_entersound = true; if (lanConfig_cursor == -1) { if (JoiningGame && TCPIPConfig) lanConfig_cursor = 2; else lanConfig_cursor = 1; } if (StartingGame && lanConfig_cursor == 2) lanConfig_cursor = 1; lanConfig_port = DEFAULTnet_hostport; sprintf(lanConfig_portname, "%u", lanConfig_port); m_return_onerror = false; m_return_reason[0] = 0; } void M_LanConfig_Draw (void) { qpic_t *p; int basex; const char *startJoin; const char *protocol; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_multi.lmp"); basex = (320-p->width)/2; M_DrawPic (basex, 4, p); if (StartingGame) startJoin = "New Game"; else startJoin = "Join Game"; if (IPXConfig) protocol = "IPX"; else protocol = "TCP/IP"; M_Print (basex, 32, va ("%s - %s", startJoin, protocol)); basex += 8; M_Print (basex, 52, "Address:"); if (IPXConfig) M_Print (basex+9*8, 52, my_ipx_address); else M_Print (basex+9*8, 52, my_tcpip_address); M_Print (basex, lanConfig_cursor_table[0], "Port"); M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1); M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname); if (JoiningGame) { M_Print (basex, lanConfig_cursor_table[1], "Search for local games..."); M_Print (basex, 108, "Join game at:"); M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1); M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname); } else { M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1); M_Print (basex+8, lanConfig_cursor_table[1], "OK"); } M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1)); if (lanConfig_cursor == 0) M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1)); if (lanConfig_cursor == 2) M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1)); if (*m_return_reason) M_PrintWhite (basex, 148, m_return_reason); } void M_LanConfig_Key (int key) { int l; switch (key) { case K_ESCAPE: M_Menu_Net_f (); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); lanConfig_cursor--; if (lanConfig_cursor < 0) lanConfig_cursor = NUM_LANCONFIG_CMDS-1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); lanConfig_cursor++; if (lanConfig_cursor >= NUM_LANCONFIG_CMDS) lanConfig_cursor = 0; break; case K_ENTER: case K_KP_ENTER: if (lanConfig_cursor == 0) break; m_entersound = true; M_ConfigureNetSubsystem (); if (lanConfig_cursor == 1) { if (StartingGame) { M_Menu_GameOptions_f (); break; } M_Menu_Search_f(); break; } if (lanConfig_cursor == 2) { m_return_state = m_state; m_return_onerror = true; IN_Activate(); key_dest = key_game; m_state = m_none; Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) ); break; } break; case K_BACKSPACE: if (lanConfig_cursor == 0) { if (strlen(lanConfig_portname)) lanConfig_portname[strlen(lanConfig_portname)-1] = 0; } if (lanConfig_cursor == 2) { if (strlen(lanConfig_joinname)) lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0; } break; } if (StartingGame && lanConfig_cursor == 2) { if (key == K_UPARROW) lanConfig_cursor = 1; else lanConfig_cursor = 0; } l = Q_atoi(lanConfig_portname); if (l > 65535) l = lanConfig_port; else lanConfig_port = l; sprintf(lanConfig_portname, "%u", lanConfig_port); } void M_LanConfig_Char (int key) { int l; switch (lanConfig_cursor) { case 0: if (key < '0' || key > '9') return; l = strlen(lanConfig_portname); if (l < 5) { lanConfig_portname[l+1] = 0; lanConfig_portname[l] = key; } break; case 2: l = strlen(lanConfig_joinname); if (l < 21) { lanConfig_joinname[l+1] = 0; lanConfig_joinname[l] = key; } break; } } qboolean M_LanConfig_TextEntry (void) { return (lanConfig_cursor == 0 || lanConfig_cursor == 2); } //============================================================================= /* GAME OPTIONS MENU */ typedef struct { const char *name; const char *description; } level_t; level_t levels[] = { {"start", "Entrance"}, // 0 {"e1m1", "Slipgate Complex"}, // 1 {"e1m2", "Castle of the Damned"}, {"e1m3", "The Necropolis"}, {"e1m4", "The Grisly Grotto"}, {"e1m5", "Gloom Keep"}, {"e1m6", "The Door To Chthon"}, {"e1m7", "The House of Chthon"}, {"e1m8", "Ziggurat Vertigo"}, {"e2m1", "The Installation"}, // 9 {"e2m2", "Ogre Citadel"}, {"e2m3", "Crypt of Decay"}, {"e2m4", "The Ebon Fortress"}, {"e2m5", "The Wizard's Manse"}, {"e2m6", "The Dismal Oubliette"}, {"e2m7", "Underearth"}, {"e3m1", "Termination Central"}, // 16 {"e3m2", "The Vaults of Zin"}, {"e3m3", "The Tomb of Terror"}, {"e3m4", "Satan's Dark Delight"}, {"e3m5", "Wind Tunnels"}, {"e3m6", "Chambers of Torment"}, {"e3m7", "The Haunted Halls"}, {"e4m1", "The Sewage System"}, // 23 {"e4m2", "The Tower of Despair"}, {"e4m3", "The Elder God Shrine"}, {"e4m4", "The Palace of Hate"}, {"e4m5", "Hell's Atrium"}, {"e4m6", "The Pain Maze"}, {"e4m7", "Azure Agony"}, {"e4m8", "The Nameless City"}, {"end", "Shub-Niggurath's Pit"}, // 31 {"dm1", "Place of Two Deaths"}, // 32 {"dm2", "Claustrophobopolis"}, {"dm3", "The Abandoned Base"}, {"dm4", "The Bad Place"}, {"dm5", "The Cistern"}, {"dm6", "The Dark Zone"} }; //MED 01/06/97 added hipnotic levels level_t hipnoticlevels[] = { {"start", "Command HQ"}, // 0 {"hip1m1", "The Pumping Station"}, // 1 {"hip1m2", "Storage Facility"}, {"hip1m3", "The Lost Mine"}, {"hip1m4", "Research Facility"}, {"hip1m5", "Military Complex"}, {"hip2m1", "Ancient Realms"}, // 6 {"hip2m2", "The Black Cathedral"}, {"hip2m3", "The Catacombs"}, {"hip2m4", "The Crypt"}, {"hip2m5", "Mortum's Keep"}, {"hip2m6", "The Gremlin's Domain"}, {"hip3m1", "Tur Torment"}, // 12 {"hip3m2", "Pandemonium"}, {"hip3m3", "Limbo"}, {"hip3m4", "The Gauntlet"}, {"hipend", "Armagon's Lair"}, // 16 {"hipdm1", "The Edge of Oblivion"} // 17 }; //PGM 01/07/97 added rogue levels //PGM 03/02/97 added dmatch level level_t roguelevels[] = { {"start", "Split Decision"}, {"r1m1", "Deviant's Domain"}, {"r1m2", "Dread Portal"}, {"r1m3", "Judgement Call"}, {"r1m4", "Cave of Death"}, {"r1m5", "Towers of Wrath"}, {"r1m6", "Temple of Pain"}, {"r1m7", "Tomb of the Overlord"}, {"r2m1", "Tempus Fugit"}, {"r2m2", "Elemental Fury I"}, {"r2m3", "Elemental Fury II"}, {"r2m4", "Curse of Osiris"}, {"r2m5", "Wizard's Keep"}, {"r2m6", "Blood Sacrifice"}, {"r2m7", "Last Bastion"}, {"r2m8", "Source of Evil"}, {"ctf1", "Division of Change"} }; typedef struct { const char *description; int firstLevel; int levels; } episode_t; episode_t episodes[] = { {"Welcome to Quake", 0, 1}, {"Doomed Dimension", 1, 8}, {"Realm of Black Magic", 9, 7}, {"Netherworld", 16, 7}, {"The Elder World", 23, 8}, {"Final Level", 31, 1}, {"Deathmatch Arena", 32, 6} }; //MED 01/06/97 added hipnotic episodes episode_t hipnoticepisodes[] = { {"Scourge of Armagon", 0, 1}, {"Fortress of the Dead", 1, 5}, {"Dominion of Darkness", 6, 6}, {"The Rift", 12, 4}, {"Final Level", 16, 1}, {"Deathmatch Arena", 17, 1} }; //PGM 01/07/97 added rogue episodes //PGM 03/02/97 added dmatch episode episode_t rogueepisodes[] = { {"Introduction", 0, 1}, {"Hell's Fortress", 1, 7}, {"Corridors of Time", 8, 8}, {"Deathmatch Arena", 16, 1} }; int startepisode; int startlevel; int maxplayers; qboolean m_serverInfoMessage = false; double m_serverInfoMessageTime; void M_Menu_GameOptions_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_gameoptions; m_entersound = true; if (maxplayers == 0) maxplayers = svs.maxclients; if (maxplayers < 2) maxplayers = svs.maxclientslimit; } int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120}; #define NUM_GAMEOPTIONS 9 int gameoptions_cursor; void M_GameOptions_Draw (void) { qpic_t *p; int x; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_DrawTextBox (152, 32, 10, 1); M_Print (160, 40, "begin game"); M_Print (0, 56, " Max players"); M_Print (160, 56, va("%i", maxplayers) ); M_Print (0, 64, " Game Type"); if (coop.value) M_Print (160, 64, "Cooperative"); else M_Print (160, 64, "Deathmatch"); M_Print (0, 72, " Teamplay"); if (rogue) { const char *msg; switch((int)teamplay.value) { case 1: msg = "No Friendly Fire"; break; case 2: msg = "Friendly Fire"; break; case 3: msg = "Tag"; break; case 4: msg = "Capture the Flag"; break; case 5: msg = "One Flag CTF"; break; case 6: msg = "Three Team CTF"; break; default: msg = "Off"; break; } M_Print (160, 72, msg); } else { const char *msg; switch((int)teamplay.value) { case 1: msg = "No Friendly Fire"; break; case 2: msg = "Friendly Fire"; break; default: msg = "Off"; break; } M_Print (160, 72, msg); } M_Print (0, 80, " Skill"); if (skill.value == 0) M_Print (160, 80, "Easy difficulty"); else if (skill.value == 1) M_Print (160, 80, "Normal difficulty"); else if (skill.value == 2) M_Print (160, 80, "Hard difficulty"); else M_Print (160, 80, "Nightmare difficulty"); M_Print (0, 88, " Frag Limit"); if (fraglimit.value == 0) M_Print (160, 88, "none"); else M_Print (160, 88, va("%i frags", (int)fraglimit.value)); M_Print (0, 96, " Time Limit"); if (timelimit.value == 0) M_Print (160, 96, "none"); else M_Print (160, 96, va("%i minutes", (int)timelimit.value)); M_Print (0, 112, " Episode"); // MED 01/06/97 added hipnotic episodes if (hipnotic) M_Print (160, 112, hipnoticepisodes[startepisode].description); // PGM 01/07/97 added rogue episodes else if (rogue) M_Print (160, 112, rogueepisodes[startepisode].description); else M_Print (160, 112, episodes[startepisode].description); M_Print (0, 120, " Level"); // MED 01/06/97 added hipnotic episodes if (hipnotic) { M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description); M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name); } // PGM 01/07/97 added rogue episodes else if (rogue) { M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description); M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name); } else { M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description); M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name); } // line cursor M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1)); if (m_serverInfoMessage) { if ((realtime - m_serverInfoMessageTime) < 5.0) { x = (320-26*8)/2; M_DrawTextBox (x, 138, 24, 4); x += 8; M_Print (x, 146, " More than 4 players "); M_Print (x, 154, " requires using command "); M_Print (x, 162, "line parameters; please "); M_Print (x, 170, " see techinfo.txt. "); } else { m_serverInfoMessage = false; } } } void M_NetStart_Change (int dir) { int count; float f; switch (gameoptions_cursor) { case 1: maxplayers += dir; if (maxplayers > svs.maxclientslimit) { maxplayers = svs.maxclientslimit; m_serverInfoMessage = true; m_serverInfoMessageTime = realtime; } if (maxplayers < 2) maxplayers = 2; break; case 2: Cvar_Set ("coop", coop.value ? "0" : "1"); break; case 3: count = (rogue) ? 6 : 2; f = teamplay.value + dir; if (f > count) f = 0; else if (f < 0) f = count; Cvar_SetValue ("teamplay", f); break; case 4: f = skill.value + dir; if (f > 3) f = 0; else if (f < 0) f = 3; Cvar_SetValue ("skill", f); break; case 5: f = fraglimit.value + dir * 10; if (f > 100) f = 0; else if (f < 0) f = 100; Cvar_SetValue ("fraglimit", f); break; case 6: f = timelimit.value + dir * 5; if (f > 60) f = 0; else if (f < 0) f = 60; Cvar_SetValue ("timelimit", f); break; case 7: startepisode += dir; //MED 01/06/97 added hipnotic count if (hipnotic) count = 6; //PGM 01/07/97 added rogue count //PGM 03/02/97 added 1 for dmatch episode else if (rogue) count = 4; else if (registered.value) count = 7; else count = 2; if (startepisode < 0) startepisode = count - 1; if (startepisode >= count) startepisode = 0; startlevel = 0; break; case 8: startlevel += dir; //MED 01/06/97 added hipnotic episodes if (hipnotic) count = hipnoticepisodes[startepisode].levels; //PGM 01/06/97 added hipnotic episodes else if (rogue) count = rogueepisodes[startepisode].levels; else count = episodes[startepisode].levels; if (startlevel < 0) startlevel = count - 1; if (startlevel >= count) startlevel = 0; break; } } void M_GameOptions_Key (int key) { switch (key) { case K_ESCAPE: M_Menu_Net_f (); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); gameoptions_cursor--; if (gameoptions_cursor < 0) gameoptions_cursor = NUM_GAMEOPTIONS-1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); gameoptions_cursor++; if (gameoptions_cursor >= NUM_GAMEOPTIONS) gameoptions_cursor = 0; break; case K_LEFTARROW: if (gameoptions_cursor == 0) break; S_LocalSound ("misc/menu3.wav"); M_NetStart_Change (-1); break; case K_RIGHTARROW: if (gameoptions_cursor == 0) break; S_LocalSound ("misc/menu3.wav"); M_NetStart_Change (1); break; case K_ENTER: case K_KP_ENTER: S_LocalSound ("misc/menu2.wav"); if (gameoptions_cursor == 0) { if (sv.active) Cbuf_AddText ("disconnect\n"); Cbuf_AddText ("listen 0\n"); // so host_netport will be re-examined Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) ); SCR_BeginLoadingPlaque (); if (hipnotic) Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) ); else if (rogue) Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) ); else Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) ); return; } M_NetStart_Change (1); break; } } //============================================================================= /* SEARCH MENU */ qboolean searchComplete = false; double searchCompleteTime; void M_Menu_Search_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_search; m_entersound = false; slistSilent = true; slistLocal = false; searchComplete = false; NET_Slist_f(); } void M_Search_Draw (void) { qpic_t *p; int x; p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); x = (320/2) - ((12*8)/2) + 4; M_DrawTextBox (x-8, 32, 12, 1); M_Print (x, 40, "Searching..."); if(slistInProgress) { NET_Poll(); return; } if (! searchComplete) { searchComplete = true; searchCompleteTime = realtime; } if (hostCacheCount) { M_Menu_ServerList_f (); return; } M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found"); if ((realtime - searchCompleteTime) < 3.0) return; M_Menu_LanConfig_f (); } void M_Search_Key (int key) { } //============================================================================= /* SLIST MENU */ int slist_cursor; qboolean slist_sorted; void M_Menu_ServerList_f (void) { IN_Deactivate(modestate == MS_WINDOWED); key_dest = key_menu; m_state = m_slist; m_entersound = true; slist_cursor = 0; m_return_onerror = false; m_return_reason[0] = 0; slist_sorted = false; } void M_ServerList_Draw (void) { int n; qpic_t *p; if (!slist_sorted) { slist_sorted = true; NET_SlistSort (); } p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); for (n = 0; n < hostCacheCount; n++) M_Print (16, 32 + 8*n, NET_SlistPrintServer (n)); M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1)); if (*m_return_reason) M_PrintWhite (16, 148, m_return_reason); } void M_ServerList_Key (int k) { switch (k) { case K_ESCAPE: M_Menu_LanConfig_f (); break; case K_SPACE: M_Menu_Search_f (); break; case K_UPARROW: case K_LEFTARROW: S_LocalSound ("misc/menu1.wav"); slist_cursor--; if (slist_cursor < 0) slist_cursor = hostCacheCount - 1; break; case K_DOWNARROW: case K_RIGHTARROW: S_LocalSound ("misc/menu1.wav"); slist_cursor++; if (slist_cursor >= hostCacheCount) slist_cursor = 0; break; case K_ENTER: case K_KP_ENTER: S_LocalSound ("misc/menu2.wav"); m_return_state = m_state; m_return_onerror = true; slist_sorted = false; IN_Activate(); key_dest = key_game; m_state = m_none; Cbuf_AddText ( va ("connect \"%s\"\n", NET_SlistPrintServerName(slist_cursor)) ); break; default: break; } } //============================================================================= /* Menu Subsystem */ void M_Init (void) { Cmd_AddCommand ("togglemenu", M_ToggleMenu_f); Cmd_AddCommand ("menu_main", M_Menu_Main_f); Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f); Cmd_AddCommand ("menu_load", M_Menu_Load_f); Cmd_AddCommand ("menu_save", M_Menu_Save_f); Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f); Cmd_AddCommand ("menu_setup", M_Menu_Setup_f); Cmd_AddCommand ("menu_options", M_Menu_Options_f); Cmd_AddCommand ("menu_keys", M_Menu_Keys_f); Cmd_AddCommand ("menu_video", M_Menu_Video_f); Cmd_AddCommand ("help", M_Menu_Help_f); Cmd_AddCommand ("menu_quit", M_Menu_Quit_f); } void M_Draw (void) { if (m_state == m_none || key_dest != key_menu) return; if (!m_recursiveDraw) { if (scr_con_current) { Draw_ConsoleBackground (); S_ExtraUpdate (); } Draw_FadeScreen (); //johnfitz -- fade even if console fills screen } else { m_recursiveDraw = false; } GL_SetCanvas (CANVAS_MENU); //johnfitz switch (m_state) { case m_none: break; case m_main: M_Main_Draw (); break; case m_singleplayer: M_SinglePlayer_Draw (); break; case m_load: M_Load_Draw (); break; case m_save: M_Save_Draw (); break; case m_multiplayer: M_MultiPlayer_Draw (); break; case m_setup: M_Setup_Draw (); break; case m_net: M_Net_Draw (); break; case m_options: M_Options_Draw (); break; case m_keys: M_Keys_Draw (); break; case m_video: M_Video_Draw (); break; case m_help: M_Help_Draw (); break; case m_quit: if (!fitzmode) { /* QuakeSpasm customization: */ /* Quit now! S.A. */ key_dest = key_console; Host_Quit_f (); } M_Quit_Draw (); break; case m_lanconfig: M_LanConfig_Draw (); break; case m_gameoptions: M_GameOptions_Draw (); break; case m_search: M_Search_Draw (); break; case m_slist: M_ServerList_Draw (); break; } if (m_entersound) { S_LocalSound ("misc/menu2.wav"); m_entersound = false; } S_ExtraUpdate (); } void M_Keydown (int key) { switch (m_state) { case m_none: return; case m_main: M_Main_Key (key); return; case m_singleplayer: M_SinglePlayer_Key (key); return; case m_load: M_Load_Key (key); return; case m_save: M_Save_Key (key); return; case m_multiplayer: M_MultiPlayer_Key (key); return; case m_setup: M_Setup_Key (key); return; case m_net: M_Net_Key (key); return; case m_options: M_Options_Key (key); return; case m_keys: M_Keys_Key (key); return; case m_video: M_Video_Key (key); return; case m_help: M_Help_Key (key); return; case m_quit: M_Quit_Key (key); return; case m_lanconfig: M_LanConfig_Key (key); return; case m_gameoptions: M_GameOptions_Key (key); return; case m_search: M_Search_Key (key); break; case m_slist: M_ServerList_Key (key); return; } } void M_Charinput (int key) { switch (m_state) { case m_setup: M_Setup_Char (key); return; case m_quit: M_Quit_Char (key); return; case m_lanconfig: M_LanConfig_Char (key); return; default: return; } } qboolean M_TextEntry (void) { switch (m_state) { case m_setup: return M_Setup_TextEntry (); case m_quit: return M_Quit_TextEntry (); case m_lanconfig: return M_LanConfig_TextEntry (); default: return false; } } void M_ConfigureNetSubsystem(void) { // enable/disable net systems to match desired config Cbuf_AddText ("stopdemo\n"); if (IPXConfig || TCPIPConfig) net_hostport = lanConfig_port; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/r_brush.c�������������������������������������������������������������������0000644�0000000�0000000�00000076707�12577611311�015354� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // r_brush.c: brush model rendering. renamed from r_surf.c #include "quakedef.h" extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater; //johnfitz extern cvar_t gl_zfix; // QuakeSpasm z-fighting fix int gl_lightmap_format; int lightmap_bytes; #define BLOCK_WIDTH 128 #define BLOCK_HEIGHT 128 gltexture_t *lightmap_textures[MAX_LIGHTMAPS]; //johnfitz -- changed to an array unsigned blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3]; //johnfitz -- was 18*18, added lit support (*3) and loosened surface extents maximum (BLOCK_WIDTH*BLOCK_HEIGHT) typedef struct glRect_s { unsigned char l,t,w,h; } glRect_t; glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; qboolean lightmap_modified[MAX_LIGHTMAPS]; glRect_t lightmap_rectchange[MAX_LIGHTMAPS]; int allocated[MAX_LIGHTMAPS][BLOCK_WIDTH]; int last_lightmap_allocated; //ericw -- optimization: remember the index of the last lightmap AllocBlock stored a surf in // the lightmap texture data needs to be kept in // main memory so texsubimage can update properly byte lightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT]; /* =============== R_TextureAnimation -- johnfitz -- added "frame" param to eliminate use of "currententity" global Returns the proper texture for a given time and base texture =============== */ texture_t *R_TextureAnimation (texture_t *base, int frame) { int relative; int count; if (frame) if (base->alternate_anims) base = base->alternate_anims; if (!base->anim_total) return base; relative = (int)(cl.time*10) % base->anim_total; count = 0; while (base->anim_min > relative || base->anim_max <= relative) { base = base->anim_next; if (!base) Sys_Error ("R_TextureAnimation: broken cycle"); if (++count > 100) Sys_Error ("R_TextureAnimation: infinite cycle"); } return base; } /* ================ DrawGLPoly ================ */ void DrawGLPoly (glpoly_t *p) { float *v; int i; glBegin (GL_POLYGON); v = p->verts[0]; for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE) { glTexCoord2f (v[3], v[4]); glVertex3fv (v); } glEnd (); } /* ================ DrawGLTriangleFan -- johnfitz -- like DrawGLPoly but for r_showtris ================ */ void DrawGLTriangleFan (glpoly_t *p) { float *v; int i; glBegin (GL_TRIANGLE_FAN); v = p->verts[0]; for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE) { glVertex3fv (v); } glEnd (); } /* ============================================================= BRUSH MODELS ============================================================= */ #if 0 /* ================ R_DrawSequentialPoly -- johnfitz -- rewritten ================ */ void R_DrawSequentialPoly (msurface_t *s) { glpoly_t *p; texture_t *t; float *v; float entalpha; int i; t = R_TextureAnimation (s->texinfo->texture, currententity->frame); entalpha = ENTALPHA_DECODE(currententity->alpha); // drawflat if (r_drawflat_cheatsafe) { if ((s->flags & SURF_DRAWTURB) && r_oldwater.value) { for (p = s->polys->next; p; p = p->next) { srand((unsigned int) (uintptr_t) p); glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); DrawGLPoly (p); rs_brushpasses++; } return; } srand((unsigned int) (uintptr_t) s->polys); glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); DrawGLPoly (s->polys); rs_brushpasses++; return; } // fullbright if ((r_fullbright_cheatsafe) && !(s->flags & SURF_DRAWTILED)) { if (entalpha < 1) { glDepthMask(GL_FALSE); glEnable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1, 1, 1, entalpha); } if (s->flags & SURF_DRAWFENCE) glEnable (GL_ALPHA_TEST); // Flip on alpha test GL_Bind (t->gltexture); DrawGLPoly (s->polys); rs_brushpasses++; if (s->flags & SURF_DRAWFENCE) glDisable (GL_ALPHA_TEST); // Flip alpha test back off if (entalpha < 1) { glDepthMask(GL_TRUE); glDisable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3f(1, 1, 1); } goto fullbrights; } // r_lightmap if (r_lightmap_cheatsafe) { if (s->flags & SURF_DRAWTILED) { glDisable (GL_TEXTURE_2D); DrawGLPoly (s->polys); glEnable (GL_TEXTURE_2D); rs_brushpasses++; return; } R_RenderDynamicLightmaps (s); GL_Bind (lightmap_textures[s->lightmaptexturenum]); if (!gl_overbright.value) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(0.5, 0.5, 0.5); } glBegin (GL_POLYGON); v = s->polys->verts[0]; for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE) { glTexCoord2f (v[5], v[6]); glVertex3fv (v); } glEnd (); if (!gl_overbright.value) { glColor3f(1,1,1); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } rs_brushpasses++; return; } // sky poly -- skip it, already handled in gl_sky.c if (s->flags & SURF_DRAWSKY) return; // water poly if (s->flags & SURF_DRAWTURB) { if (currententity->alpha == ENTALPHA_DEFAULT) entalpha = CLAMP(0.0, GL_WaterAlphaForSurface(s), 1.0); if (entalpha < 1) { glDepthMask(GL_FALSE); glEnable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1, 1, 1, entalpha); } if (r_oldwater.value) { GL_Bind (s->texinfo->texture->gltexture); for (p = s->polys->next; p; p = p->next) { DrawWaterPoly (p); rs_brushpasses++; } rs_brushpasses++; } else { GL_Bind (s->texinfo->texture->warpimage); s->texinfo->texture->update_warp = true; // FIXME: one frame too late! DrawGLPoly (s->polys); rs_brushpasses++; } if (entalpha < 1) { glDepthMask(GL_TRUE); glDisable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3f(1, 1, 1); } return; } // missing texture if (s->flags & SURF_NOTEXTURE) { if (entalpha < 1) { glDepthMask(GL_FALSE); glEnable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1, 1, 1, entalpha); } GL_Bind (t->gltexture); DrawGLPoly (s->polys); rs_brushpasses++; if (entalpha < 1) { glDepthMask(GL_TRUE); glDisable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3f(1, 1, 1); } return; } // lightmapped poly if (entalpha < 1) { glDepthMask(GL_FALSE); glEnable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1, 1, 1, entalpha); } else glColor3f(1, 1, 1); if (s->flags & SURF_DRAWFENCE) glEnable (GL_ALPHA_TEST); // Flip on alpha test if (gl_overbright.value) { if (gl_texture_env_combine && gl_mtexable) //case 1: texture and lightmap in one pass, overbright using texture combiners { GL_DisableMultitexture(); // selects TEXTURE0 GL_Bind (t->gltexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_EnableMultitexture(); // selects TEXTURE1 GL_Bind (lightmap_textures[s->lightmaptexturenum]); R_RenderDynamicLightmaps (s); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); glBegin(GL_POLYGON); v = s->polys->verts[0]; for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE) { GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]); GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]); glVertex3fv (v); } glEnd (); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DisableMultitexture (); rs_brushpasses++; } else if (entalpha < 1 || (s->flags & SURF_DRAWFENCE)) //case 2: can't do multipass if entity has alpha, so just draw the texture { GL_Bind (t->gltexture); DrawGLPoly (s->polys); rs_brushpasses++; } else //case 3: texture in one pass, lightmap in second pass using 2x modulation blend func, fog in third pass { //first pass -- texture with no fog Fog_DisableGFog (); GL_Bind (t->gltexture); DrawGLPoly (s->polys); Fog_EnableGFog (); rs_brushpasses++; //second pass -- lightmap with black fog, modulate blended R_RenderDynamicLightmaps (s); GL_Bind (lightmap_textures[s->lightmaptexturenum]); glDepthMask (GL_FALSE); glEnable (GL_BLEND); glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); //2x modulate Fog_StartAdditive (); glBegin (GL_POLYGON); v = s->polys->verts[0]; for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE) { glTexCoord2f (v[5], v[6]); glVertex3fv (v); } glEnd (); Fog_StopAdditive (); rs_brushpasses++; //third pass -- black geo with normal fog, additive blended if (Fog_GetDensity() > 0) { glBlendFunc(GL_ONE, GL_ONE); //add glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(0,0,0); DrawGLPoly (s->polys); glColor3f(1,1,1); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); rs_brushpasses++; } glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable (GL_BLEND); glDepthMask (GL_TRUE); } } else { if (gl_mtexable) //case 4: texture and lightmap in one pass, regular modulation { GL_DisableMultitexture(); // selects TEXTURE0 GL_Bind (t->gltexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_EnableMultitexture(); // selects TEXTURE1 GL_Bind (lightmap_textures[s->lightmaptexturenum]); R_RenderDynamicLightmaps (s); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBegin(GL_POLYGON); v = s->polys->verts[0]; for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE) { GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]); GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]); glVertex3fv (v); } glEnd (); GL_DisableMultitexture (); rs_brushpasses++; } else if (entalpha < 1 || (s->flags & SURF_DRAWFENCE)) //case 5: can't do multipass if entity has alpha, so just draw the texture { GL_Bind (t->gltexture); DrawGLPoly (s->polys); rs_brushpasses++; } else //case 6: texture in one pass, lightmap in a second pass, fog in third pass { //first pass -- texture with no fog Fog_DisableGFog (); GL_Bind (t->gltexture); DrawGLPoly (s->polys); Fog_EnableGFog (); rs_brushpasses++; //second pass -- lightmap with black fog, modulate blended R_RenderDynamicLightmaps (s); GL_Bind (lightmap_textures[s->lightmaptexturenum]); glDepthMask (GL_FALSE); glEnable (GL_BLEND); glBlendFunc (GL_ZERO, GL_SRC_COLOR); //modulate Fog_StartAdditive (); glBegin (GL_POLYGON); v = s->polys->verts[0]; for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE) { glTexCoord2f (v[5], v[6]); glVertex3fv (v); } glEnd (); Fog_StopAdditive (); rs_brushpasses++; //third pass -- black geo with normal fog, additive blended if (Fog_GetDensity() > 0) { glBlendFunc(GL_ONE, GL_ONE); //add glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(0,0,0); DrawGLPoly (s->polys); glColor3f(1,1,1); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); rs_brushpasses++; } glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable (GL_BLEND); glDepthMask (GL_TRUE); } } if (entalpha < 1) { glDepthMask(GL_TRUE); glDisable(GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3f(1, 1, 1); } if (s->flags & SURF_DRAWFENCE) glDisable (GL_ALPHA_TEST); // Flip alpha test back off fullbrights: if (gl_fullbrights.value && t->fullbright) { glDepthMask (GL_FALSE); glEnable (GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f (entalpha, entalpha, entalpha); GL_Bind (t->fullbright); Fog_StartAdditive (); DrawGLPoly (s->polys); Fog_StopAdditive (); glColor3f(1, 1, 1); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable (GL_BLEND); glDepthMask (GL_TRUE); rs_brushpasses++; } } #endif /* ================= R_DrawBrushModel ================= */ void R_DrawBrushModel (entity_t *e) { int i, k; msurface_t *psurf; float dot; mplane_t *pplane; qmodel_t *clmodel; if (R_CullModelForEntity(e)) return; currententity = e; clmodel = e->model; VectorSubtract (r_refdef.vieworg, e->origin, modelorg); if (e->angles[0] || e->angles[1] || e->angles[2]) { vec3_t temp; vec3_t forward, right, up; VectorCopy (modelorg, temp); AngleVectors (e->angles, forward, right, up); modelorg[0] = DotProduct (temp, forward); modelorg[1] = -DotProduct (temp, right); modelorg[2] = DotProduct (temp, up); } psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; // calculate dynamic lighting for bmodel if it's not an // instanced model if (clmodel->firstmodelsurface != 0 && !gl_flashblend.value) { for (k=0 ; k<MAX_DLIGHTS ; k++) { if ((cl_dlights[k].die < cl.time) || (!cl_dlights[k].radius)) continue; R_MarkLights (&cl_dlights[k], k, clmodel->nodes + clmodel->hulls[0].firstclipnode); } } glPushMatrix (); e->angles[0] = -e->angles[0]; // stupid quake bug if (gl_zfix.value) { e->origin[0] -= DIST_EPSILON; e->origin[1] -= DIST_EPSILON; e->origin[2] -= DIST_EPSILON; } R_RotateForEntity (e->origin, e->angles); if (gl_zfix.value) { e->origin[0] += DIST_EPSILON; e->origin[1] += DIST_EPSILON; e->origin[2] += DIST_EPSILON; } e->angles[0] = -e->angles[0]; // stupid quake bug R_ClearTextureChains (clmodel, chain_model); for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++) { pplane = psurf->plane; dot = DotProduct (modelorg, pplane->normal) - pplane->dist; if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { R_ChainSurface (psurf, chain_model); rs_brushpolys++; } } R_DrawTextureChains (clmodel, e, chain_model); R_DrawTextureChains_Water (clmodel, e, chain_model); glPopMatrix (); } /* ================= R_DrawBrushModel_ShowTris -- johnfitz ================= */ void R_DrawBrushModel_ShowTris (entity_t *e) { int i; msurface_t *psurf; float dot; mplane_t *pplane; qmodel_t *clmodel; glpoly_t *p; if (R_CullModelForEntity(e)) return; currententity = e; clmodel = e->model; VectorSubtract (r_refdef.vieworg, e->origin, modelorg); if (e->angles[0] || e->angles[1] || e->angles[2]) { vec3_t temp; vec3_t forward, right, up; VectorCopy (modelorg, temp); AngleVectors (e->angles, forward, right, up); modelorg[0] = DotProduct (temp, forward); modelorg[1] = -DotProduct (temp, right); modelorg[2] = DotProduct (temp, up); } psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; glPushMatrix (); e->angles[0] = -e->angles[0]; // stupid quake bug R_RotateForEntity (e->origin, e->angles); e->angles[0] = -e->angles[0]; // stupid quake bug // // draw it // for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++) { pplane = psurf->plane; dot = DotProduct (modelorg, pplane->normal) - pplane->dist; if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { if ((psurf->flags & SURF_DRAWTURB) && r_oldwater.value) for (p = psurf->polys->next; p; p = p->next) DrawGLTriangleFan (p); else DrawGLTriangleFan (psurf->polys); } } glPopMatrix (); } /* ============================================================= LIGHTMAPS ============================================================= */ /* ================ R_RenderDynamicLightmaps called during rendering ================ */ void R_RenderDynamicLightmaps (msurface_t *fa) { byte *base; int maps; glRect_t *theRect; int smax, tmax; if (fa->flags & SURF_DRAWTILED) //johnfitz -- not a lightmapped surface return; // add to lightmap chain fa->polys->chain = lightmap_polys[fa->lightmaptexturenum]; lightmap_polys[fa->lightmaptexturenum] = fa->polys; // check for lightmap modification for (maps=0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++) if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps]) goto dynamic; if (fa->dlightframe == r_framecount // dynamic this frame || fa->cached_dlight) // dynamic previously { dynamic: if (r_dynamic.value) { lightmap_modified[fa->lightmaptexturenum] = true; theRect = &lightmap_rectchange[fa->lightmaptexturenum]; if (fa->light_t < theRect->t) { if (theRect->h) theRect->h += theRect->t - fa->light_t; theRect->t = fa->light_t; } if (fa->light_s < theRect->l) { if (theRect->w) theRect->w += theRect->l - fa->light_s; theRect->l = fa->light_s; } smax = (fa->extents[0]>>4)+1; tmax = (fa->extents[1]>>4)+1; if ((theRect->w + theRect->l) < (fa->light_s + smax)) theRect->w = (fa->light_s-theRect->l)+smax; if ((theRect->h + theRect->t) < (fa->light_t + tmax)) theRect->h = (fa->light_t-theRect->t)+tmax; base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT; base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes; R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes); } } } /* ======================== AllocBlock -- returns a texture number and the position inside it ======================== */ int AllocBlock (int w, int h, int *x, int *y) { int i, j; int best, best2; int texnum; // ericw -- rather than searching starting at lightmap 0 every time, // start at the last lightmap we allocated a surface in. // This makes AllocBlock much faster on large levels (can shave off 3+ seconds // of load time on a level with 180 lightmaps), at a cost of not quite packing // lightmaps as tightly vs. not doing this (uses ~5% more lightmaps) for (texnum=last_lightmap_allocated ; texnum<MAX_LIGHTMAPS ; texnum++, last_lightmap_allocated++) { best = BLOCK_HEIGHT; for (i=0 ; i<BLOCK_WIDTH-w ; i++) { best2 = 0; for (j=0 ; j<w ; j++) { if (allocated[texnum][i+j] >= best) break; if (allocated[texnum][i+j] > best2) best2 = allocated[texnum][i+j]; } if (j == w) { // this is a valid spot *x = i; *y = best = best2; } } if (best + h > BLOCK_HEIGHT) continue; for (i=0 ; i<w ; i++) allocated[texnum][*x + i] = best + h; return texnum; } Sys_Error ("AllocBlock: full"); return 0; //johnfitz -- shut up compiler } mvertex_t *r_pcurrentvertbase; qmodel_t *currentmodel; int nColinElim; /* ======================== GL_CreateSurfaceLightmap ======================== */ void GL_CreateSurfaceLightmap (msurface_t *surf) { int smax, tmax; byte *base; smax = (surf->extents[0]>>4)+1; tmax = (surf->extents[1]>>4)+1; surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t); base = lightmaps + surf->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT; base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes; R_BuildLightMap (surf, base, BLOCK_WIDTH*lightmap_bytes); } /* ================ BuildSurfaceDisplayList -- called at level load time ================ */ void BuildSurfaceDisplayList (msurface_t *fa) { int i, lindex, lnumverts; medge_t *pedges, *r_pedge; float *vec; float s, t; glpoly_t *poly; // reconstruct the polygon pedges = currentmodel->edges; lnumverts = fa->numedges; // // draw texture // poly = (glpoly_t *) Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float)); poly->next = fa->polys; fa->polys = poly; poly->numverts = lnumverts; for (i=0 ; i<lnumverts ; i++) { lindex = currentmodel->surfedges[fa->firstedge + i]; if (lindex > 0) { r_pedge = &pedges[lindex]; vec = r_pcurrentvertbase[r_pedge->v[0]].position; } else { r_pedge = &pedges[-lindex]; vec = r_pcurrentvertbase[r_pedge->v[1]].position; } s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; s /= fa->texinfo->texture->width; t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; t /= fa->texinfo->texture->height; VectorCopy (vec, poly->verts[i]); poly->verts[i][3] = s; poly->verts[i][4] = t; // // lightmap texture coordinates // s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; s -= fa->texturemins[0]; s += fa->light_s*16; s += 8; s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width; t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; t -= fa->texturemins[1]; t += fa->light_t*16; t += 8; t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height; poly->verts[i][5] = s; poly->verts[i][6] = t; } //johnfitz -- removed gl_keeptjunctions code poly->numverts = lnumverts; } /* ================== GL_BuildLightmaps -- called at level load time Builds the lightmap texture with all the surfaces from all brush models ================== */ void GL_BuildLightmaps (void) { char name[16]; byte *data; int i, j; qmodel_t *m; memset (allocated, 0, sizeof(allocated)); last_lightmap_allocated = 0; r_framecount = 1; // no dlightcache //johnfitz -- null out array (the gltexture objects themselves were already freed by Mod_ClearAll) for (i=0; i < MAX_LIGHTMAPS; i++) lightmap_textures[i] = NULL; //johnfitz gl_lightmap_format = GL_RGBA;//FIXME: hardcoded for now! switch (gl_lightmap_format) { case GL_RGBA: lightmap_bytes = 4; break; case GL_BGRA: lightmap_bytes = 4; break; default: Sys_Error ("GL_BuildLightmaps: bad lightmap format"); } for (j=1 ; j<MAX_MODELS ; j++) { m = cl.model_precache[j]; if (!m) break; if (m->name[0] == '*') continue; r_pcurrentvertbase = m->vertexes; currentmodel = m; for (i=0 ; i<m->numsurfaces ; i++) { //johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags if (m->surfaces[i].flags & SURF_DRAWTILED) continue; GL_CreateSurfaceLightmap (m->surfaces + i); BuildSurfaceDisplayList (m->surfaces + i); //johnfitz } } // // upload all lightmaps that were filled // for (i=0; i<MAX_LIGHTMAPS; i++) { if (!allocated[i][0]) break; // no more used lightmap_modified[i] = false; lightmap_rectchange[i].l = BLOCK_WIDTH; lightmap_rectchange[i].t = BLOCK_HEIGHT; lightmap_rectchange[i].w = 0; lightmap_rectchange[i].h = 0; //johnfitz -- use texture manager sprintf(name, "lightmap%03i",i); data = lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes; lightmap_textures[i] = TexMgr_LoadImage (cl.worldmodel, name, BLOCK_WIDTH, BLOCK_HEIGHT, SRC_LIGHTMAP, data, "", (src_offset_t)data, TEXPREF_LINEAR | TEXPREF_NOPICMIP); //johnfitz } //johnfitz -- warn about exceeding old limits if (i >= 64) Con_DWarning ("%i lightmaps exceeds standard limit of 64.\n", i); //johnfitz } /* ============================================================= VBO support ============================================================= */ GLuint gl_bmodel_vbo = 0; void GL_DeleteBModelVertexBuffer (void) { if (!(gl_vbo_able && gl_mtexable && gl_max_texture_units >= 3)) return; GL_DeleteBuffersFunc (1, &gl_bmodel_vbo); gl_bmodel_vbo = 0; GL_ClearBufferBindings (); } /* ================== GL_BuildBModelVertexBuffer Deletes gl_bmodel_vbo if it already exists, then rebuilds it with all surfaces from world + all brush models ================== */ void GL_BuildBModelVertexBuffer (void) { unsigned int numverts, varray_bytes, varray_index; int i, j; qmodel_t *m; float *varray; if (!(gl_vbo_able && gl_mtexable && gl_max_texture_units >= 3)) return; // ask GL for a name for our VBO GL_DeleteBuffersFunc (1, &gl_bmodel_vbo); GL_GenBuffersFunc (1, &gl_bmodel_vbo); // count all verts in all models numverts = 0; for (j=1 ; j<MAX_MODELS ; j++) { m = cl.model_precache[j]; if (!m || m->name[0] == '*' || m->type != mod_brush) continue; for (i=0 ; i<m->numsurfaces ; i++) { numverts += m->surfaces[i].numedges; } } // build vertex array varray_bytes = VERTEXSIZE * sizeof(float) * numverts; varray = (float *) malloc (varray_bytes); varray_index = 0; for (j=1 ; j<MAX_MODELS ; j++) { m = cl.model_precache[j]; if (!m || m->name[0] == '*' || m->type != mod_brush) continue; for (i=0 ; i<m->numsurfaces ; i++) { msurface_t *s = &m->surfaces[i]; s->vbo_firstvert = varray_index; memcpy (&varray[VERTEXSIZE * varray_index], s->polys->verts, VERTEXSIZE * sizeof(float) * s->numedges); varray_index += s->numedges; } } // upload to GPU GL_BindBufferFunc (GL_ARRAY_BUFFER, gl_bmodel_vbo); GL_BufferDataFunc (GL_ARRAY_BUFFER, varray_bytes, varray, GL_STATIC_DRAW); free (varray); // invalidate the cached bindings GL_ClearBufferBindings (); } /* =============== R_AddDynamicLights =============== */ void R_AddDynamicLights (msurface_t *surf) { int lnum; int sd, td; float dist, rad, minlight; vec3_t impact, local; int s, t; int i; int smax, tmax; mtexinfo_t *tex; //johnfitz -- lit support via lordhavoc float cred, cgreen, cblue, brightness; unsigned *bl; //johnfitz smax = (surf->extents[0]>>4)+1; tmax = (surf->extents[1]>>4)+1; tex = surf->texinfo; for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) { if (! (surf->dlightbits[lnum >> 5] & (1U << (lnum & 31)))) continue; // not lit by this light rad = cl_dlights[lnum].radius; dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) - surf->plane->dist; rad -= fabs(dist); minlight = cl_dlights[lnum].minlight; if (rad < minlight) continue; minlight = rad - minlight; for (i=0 ; i<3 ; i++) { impact[i] = cl_dlights[lnum].origin[i] - surf->plane->normal[i]*dist; } local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; local[0] -= surf->texturemins[0]; local[1] -= surf->texturemins[1]; //johnfitz -- lit support via lordhavoc bl = blocklights; cred = cl_dlights[lnum].color[0] * 256.0f; cgreen = cl_dlights[lnum].color[1] * 256.0f; cblue = cl_dlights[lnum].color[2] * 256.0f; //johnfitz for (t = 0 ; t<tmax ; t++) { td = local[1] - t*16; if (td < 0) td = -td; for (s=0 ; s<smax ; s++) { sd = local[0] - s*16; if (sd < 0) sd = -sd; if (sd > td) dist = sd + (td>>1); else dist = td + (sd>>1); if (dist < minlight) //johnfitz -- lit support via lordhavoc { brightness = rad - dist; bl[0] += (int) (brightness * cred); bl[1] += (int) (brightness * cgreen); bl[2] += (int) (brightness * cblue); } bl += 3; //johnfitz } } } } /* =============== R_BuildLightMap -- johnfitz -- revised for lit support via lordhavoc Combine and scale multiple lightmaps into the 8.8 format in blocklights =============== */ void R_BuildLightMap (msurface_t *surf, byte *dest, int stride) { int smax, tmax; int r,g,b; int i, j, size; byte *lightmap; unsigned scale; int maps; unsigned *bl; surf->cached_dlight = (surf->dlightframe == r_framecount); smax = (surf->extents[0]>>4)+1; tmax = (surf->extents[1]>>4)+1; size = smax*tmax; lightmap = surf->samples; if (cl.worldmodel->lightdata) { // clear to no light memset (&blocklights[0], 0, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc // add all the lightmaps if (lightmap) for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction //johnfitz -- lit support via lordhavoc bl = blocklights; for (i=0 ; i<size ; i++) { *bl++ += *lightmap++ * scale; *bl++ += *lightmap++ * scale; *bl++ += *lightmap++ * scale; } //johnfitz } // add all the dynamic lights if (surf->dlightframe == r_framecount) R_AddDynamicLights (surf); } else { // set to full bright if no light data memset (&blocklights[0], 255, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc } // bound, invert, and shift // store: switch (gl_lightmap_format) { case GL_RGBA: stride -= smax * 4; bl = blocklights; for (i=0 ; i<tmax ; i++, dest += stride) { for (j=0 ; j<smax ; j++) { if (gl_overbright.value) { r = *bl++ >> 8; g = *bl++ >> 8; b = *bl++ >> 8; } else { r = *bl++ >> 7; g = *bl++ >> 7; b = *bl++ >> 7; } if (r > 255) r = 255; *dest++ = r; if (g > 255) g = 255; *dest++ = g; if (b > 255) b = 255; *dest++ = b; *dest++ = 255; } } break; case GL_BGRA: stride -= smax * 4; bl = blocklights; for (i=0 ; i<tmax ; i++, dest += stride) { for (j=0 ; j<smax ; j++) { if (gl_overbright.value) { r = *bl++ >> 8; g = *bl++ >> 8; b = *bl++ >> 8; } else { r = *bl++ >> 7; g = *bl++ >> 7; b = *bl++ >> 7; } if (b > 255) b = 255; *dest++ = b; if (g > 255) g = 255; *dest++ = g; if (r > 255) r = 255; *dest++ = r; *dest++ = 255; } } break; default: Sys_Error ("R_BuildLightMap: bad lightmap format"); } } /* =============== R_UploadLightmap -- johnfitz -- uploads the modified lightmap to opengl if necessary assumes lightmap texture is already bound =============== */ static void R_UploadLightmap(int lmap) { glRect_t *theRect; if (!lightmap_modified[lmap]) return; lightmap_modified[lmap] = false; theRect = &lightmap_rectchange[lmap]; glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+(lmap* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes); theRect->l = BLOCK_WIDTH; theRect->t = BLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; rs_dynamiclightmaps++; } void R_UploadLightmaps (void) { int lmap; for (lmap = 0; lmap < MAX_LIGHTMAPS; lmap++) { if (!lightmap_modified[lmap]) continue; GL_Bind (lightmap_textures[lmap]); R_UploadLightmap(lmap); } } /* ================ R_RebuildAllLightmaps -- johnfitz -- called when gl_overbright gets toggled ================ */ void R_RebuildAllLightmaps (void) { int i, j; qmodel_t *mod; msurface_t *fa; byte *base; if (!cl.worldmodel) // is this the correct test? return; //for each surface in each model, rebuild lightmap with new scale for (i=1; i<MAX_MODELS; i++) { if (!(mod = cl.model_precache[i])) continue; fa = &mod->surfaces[mod->firstmodelsurface]; for (j=0; j<mod->nummodelsurfaces; j++, fa++) { if (fa->flags & SURF_DRAWTILED) continue; base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT; base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes; R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes); } } //for each lightmap, upload it for (i=0; i<MAX_LIGHTMAPS; i++) { if (!allocated[i][0]) break; GL_Bind (lightmap_textures[i]); glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, BLOCK_WIDTH, BLOCK_HEIGHT, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes); } } ���������������������������������������������������������quakespasm-0.91.0/Quake/net.h�����������������������������������������������������������������������0000644�0000000�0000000�00000006640�12506735242�014472� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2009-2010 Ozkan Sezer Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* net.h quake's interface to the networking layer network functions and data, common to the whole engine */ #ifndef _QUAKE_NET_H #define _QUAKE_NET_H #define NET_NAMELEN 64 #define NET_MAXMESSAGE 64000 /* ericw -- was 32000 */ extern int DEFAULTnet_hostport; extern int net_hostport; extern cvar_t hostname; extern double net_time; extern sizebuf_t net_message; extern int net_activeconnections; void NET_Init (void); void NET_Shutdown (void); struct qsocket_s *NET_CheckNewConnections (void); // returns a new connection number if there is one pending, else -1 struct qsocket_s *NET_Connect (const char *host); // called by client to connect to a host. Returns -1 if not able to double NET_QSocketGetTime (const struct qsocket_s *sock); const char *NET_QSocketGetAddressString (const struct qsocket_s *sock); qboolean NET_CanSendMessage (struct qsocket_s *sock); // Returns true or false if the given qsocket can currently accept a // message to be transmitted. int NET_GetMessage (struct qsocket_s *sock); // returns data in net_message sizebuf // returns 0 if no data is waiting // returns 1 if a message was received // returns 2 if an unreliable message was received // returns -1 if the connection died int NET_SendMessage (struct qsocket_s *sock, sizebuf_t *data); int NET_SendUnreliableMessage (struct qsocket_s *sock, sizebuf_t *data); // returns 0 if the message connot be delivered reliably, but the connection // is still considered valid // returns 1 if the message was sent properly // returns -1 if the connection died int NET_SendToAll(sizebuf_t *data, double blocktime); // This is a reliable *blocking* send to all attached clients. void NET_Close (struct qsocket_s *sock); // if a dead connection is returned by a get or send function, this function // should be called when it is convenient // Server calls when a client is kicked off for a game related misbehavior // like an illegal protocal conversation. Client calls when disconnecting // from a server. // A netcon_t number will not be reused until this function is called for it void NET_Poll (void); // Server list related globals: extern qboolean slistInProgress; extern qboolean slistSilent; extern qboolean slistLocal; extern int hostCacheCount; void NET_Slist_f (void); void NET_SlistSort (void); const char *NET_SlistPrintServer (int n); const char *NET_SlistPrintServerName (int n); /* FIXME: driver related, but public: */ extern qboolean ipxAvailable; extern qboolean tcpipAvailable; extern char my_ipx_address[NET_NAMELEN]; extern char my_tcpip_address[NET_NAMELEN]; #endif /* _QUAKE_NET_H */ ������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/common.c��������������������������������������������������������������������0000644�0000000�0000000�00000134140�12560420775�015166� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // common.c -- misc functions used in client and server #include "quakedef.h" #include "q_ctype.h" #include <errno.h> static char *largv[MAX_NUM_ARGVS + 1]; static char argvdummy[] = " "; int safemode; cvar_t registered = {"registered","1",CVAR_ROM}; /* set to correct value in COM_CheckRegistered() */ cvar_t cmdline = {"cmdline","",CVAR_ROM/*|CVAR_SERVERINFO*/}; /* sending cmdline upon CCREQ_RULE_INFO is evil */ static qboolean com_modified; // set true if using non-id files qboolean fitzmode; static void COM_Path_f (void); // if a packfile directory differs from this, it is assumed to be hacked #define PAK0_COUNT 339 /* id1/pak0.pak - v1.0x */ #define PAK0_CRC_V100 13900 /* id1/pak0.pak - v1.00 */ #define PAK0_CRC_V101 62751 /* id1/pak0.pak - v1.01 */ #define PAK0_CRC_V106 32981 /* id1/pak0.pak - v1.06 */ #define PAK0_CRC (PAK0_CRC_V106) #define PAK0_COUNT_V091 308 /* id1/pak0.pak - v0.91/0.92, not supported */ #define PAK0_CRC_V091 28804 /* id1/pak0.pak - v0.91/0.92, not supported */ char com_token[1024]; int com_argc; char **com_argv; #define CMDLINE_LENGTH 256 /* johnfitz -- mirrored in cmd.c */ char com_cmdline[CMDLINE_LENGTH]; qboolean standard_quake = true, rogue, hipnotic; // this graphic needs to be in the pak file to use registered features static unsigned short pop[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000, 0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000, 0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600, 0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563, 0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564, 0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564, 0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563, 0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500, 0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200, 0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000, 0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000 }; /* All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources. The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is only used during filesystem initialization. The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't. The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory specified, when a file is found by the normal search path, it will be mirrored into the cache directory, then opened there. FIXME: The file "parms.txt" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently. This could be used to add a "-sspeed 22050" for the high quality sound edition. Because they are added at the end, they will not override an explicit setting on the original command line. */ //============================================================================ // ClearLink is used for new headnodes void ClearLink (link_t *l) { l->prev = l->next = l; } void RemoveLink (link_t *l) { l->next->prev = l->prev; l->prev->next = l->next; } void InsertLinkBefore (link_t *l, link_t *before) { l->next = before; l->prev = before->prev; l->prev->next = l; l->next->prev = l; } void InsertLinkAfter (link_t *l, link_t *after) { l->next = after->next; l->prev = after; l->prev->next = l; l->next->prev = l; } /* ============================================================================ LIBRARY REPLACEMENT FUNCTIONS ============================================================================ */ int q_strcasecmp(const char * s1, const char * s2) { const char * p1 = s1; const char * p2 = s2; char c1, c2; if (p1 == p2) return 0; do { c1 = q_tolower (*p1++); c2 = q_tolower (*p2++); if (c1 == '\0') break; } while (c1 == c2); return (int)(c1 - c2); } int q_strncasecmp(const char *s1, const char *s2, size_t n) { const char * p1 = s1; const char * p2 = s2; char c1, c2; if (p1 == p2 || n == 0) return 0; do { c1 = q_tolower (*p1++); c2 = q_tolower (*p2++); if (c1 == '\0' || c1 != c2) break; } while (--n > 0); return (int)(c1 - c2); } char *q_strlwr (char *str) { char *c; c = str; while (*c) { *c = q_tolower(*c); c++; } return str; } char *q_strupr (char *str) { char *c; c = str; while (*c) { *c = q_toupper(*c); c++; } return str; } /* platform dependant (v)snprintf function names: */ #if defined(_WIN32) #define snprintf_func _snprintf #define vsnprintf_func _vsnprintf #else #define snprintf_func snprintf #define vsnprintf_func vsnprintf #endif int q_vsnprintf(char *str, size_t size, const char *format, va_list args) { int ret; ret = vsnprintf_func (str, size, format, args); if (ret < 0) ret = (int)size; if (size == 0) /* no buffer */ return ret; if ((size_t)ret >= size) str[size - 1] = '\0'; return ret; } int q_snprintf (char *str, size_t size, const char *format, ...) { int ret; va_list argptr; va_start (argptr, format); ret = q_vsnprintf (str, size, format, argptr); va_end (argptr); return ret; } void Q_memset (void *dest, int fill, size_t count) { size_t i; if ( (((size_t)dest | count) & 3) == 0) { count >>= 2; fill = fill | (fill<<8) | (fill<<16) | (fill<<24); for (i = 0; i < count; i++) ((int *)dest)[i] = fill; } else for (i = 0; i < count; i++) ((byte *)dest)[i] = fill; } void Q_memcpy (void *dest, const void *src, size_t count) { size_t i; if (( ( (size_t)dest | (size_t)src | count) & 3) == 0 ) { count >>= 2; for (i = 0; i < count; i++) ((int *)dest)[i] = ((int *)src)[i]; } else for (i = 0; i < count; i++) ((byte *)dest)[i] = ((byte *)src)[i]; } int Q_memcmp (const void *m1, const void *m2, size_t count) { while(count) { count--; if (((byte *)m1)[count] != ((byte *)m2)[count]) return -1; } return 0; } void Q_strcpy (char *dest, const char *src) { while (*src) { *dest++ = *src++; } *dest++ = 0; } void Q_strncpy (char *dest, const char *src, int count) { while (*src && count--) { *dest++ = *src++; } if (count) *dest++ = 0; } int Q_strlen (const char *str) { int count; count = 0; while (str[count]) count++; return count; } char *Q_strrchr(const char *s, char c) { int len = Q_strlen(s); s += len; while (len--) { if (*--s == c) return (char *)s; } return NULL; } void Q_strcat (char *dest, const char *src) { dest += Q_strlen(dest); Q_strcpy (dest, src); } int Q_strcmp (const char *s1, const char *s2) { while (1) { if (*s1 != *s2) return -1; // strings not equal if (!*s1) return 0; // strings are equal s1++; s2++; } return -1; } int Q_strncmp (const char *s1, const char *s2, int count) { while (1) { if (!count--) return 0; if (*s1 != *s2) return -1; // strings not equal if (!*s1) return 0; // strings are equal s1++; s2++; } return -1; } int Q_atoi (const char *str) { int val; int sign; int c; if (*str == '-') { sign = -1; str++; } else sign = 1; val = 0; // // check for hex // if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) { str += 2; while (1) { c = *str++; if (c >= '0' && c <= '9') val = (val<<4) + c - '0'; else if (c >= 'a' && c <= 'f') val = (val<<4) + c - 'a' + 10; else if (c >= 'A' && c <= 'F') val = (val<<4) + c - 'A' + 10; else return val*sign; } } // // check for character // if (str[0] == '\'') { return sign * str[1]; } // // assume decimal // while (1) { c = *str++; if (c <'0' || c > '9') return val*sign; val = val*10 + c - '0'; } return 0; } float Q_atof (const char *str) { double val; int sign; int c; int decimal, total; if (*str == '-') { sign = -1; str++; } else sign = 1; val = 0; // // check for hex // if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) { str += 2; while (1) { c = *str++; if (c >= '0' && c <= '9') val = (val*16) + c - '0'; else if (c >= 'a' && c <= 'f') val = (val*16) + c - 'a' + 10; else if (c >= 'A' && c <= 'F') val = (val*16) + c - 'A' + 10; else return val*sign; } } // // check for character // if (str[0] == '\'') { return sign * str[1]; } // // assume decimal // decimal = -1; total = 0; while (1) { c = *str++; if (c == '.') { decimal = total; continue; } if (c <'0' || c > '9') break; val = val*10 + c - '0'; total++; } if (decimal == -1) return val*sign; while (total > decimal) { val /= 10; total--; } return val*sign; } /* ============================================================================ BYTE ORDER FUNCTIONS ============================================================================ */ qboolean host_bigendian; short (*BigShort) (short l); short (*LittleShort) (short l); int (*BigLong) (int l); int (*LittleLong) (int l); float (*BigFloat) (float l); float (*LittleFloat) (float l); short ShortSwap (short l) { byte b1, b2; b1 = l&255; b2 = (l>>8)&255; return (b1<<8) + b2; } short ShortNoSwap (short l) { return l; } int LongSwap (int l) { byte b1, b2, b3, b4; b1 = l&255; b2 = (l>>8)&255; b3 = (l>>16)&255; b4 = (l>>24)&255; return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; } int LongNoSwap (int l) { return l; } float FloatSwap (float f) { union { float f; byte b[4]; } dat1, dat2; dat1.f = f; dat2.b[0] = dat1.b[3]; dat2.b[1] = dat1.b[2]; dat2.b[2] = dat1.b[1]; dat2.b[3] = dat1.b[0]; return dat2.f; } float FloatNoSwap (float f) { return f; } /* ============================================================================== MESSAGE IO FUNCTIONS Handles byte ordering and avoids alignment errors ============================================================================== */ // // writing functions // void MSG_WriteChar (sizebuf_t *sb, int c) { byte *buf; #ifdef PARANOID if (c < -128 || c > 127) Sys_Error ("MSG_WriteChar: range error"); #endif buf = (byte *) SZ_GetSpace (sb, 1); buf[0] = c; } void MSG_WriteByte (sizebuf_t *sb, int c) { byte *buf; #ifdef PARANOID if (c < 0 || c > 255) Sys_Error ("MSG_WriteByte: range error"); #endif buf = (byte *) SZ_GetSpace (sb, 1); buf[0] = c; } void MSG_WriteShort (sizebuf_t *sb, int c) { byte *buf; #ifdef PARANOID if (c < ((short)0x8000) || c > (short)0x7fff) Sys_Error ("MSG_WriteShort: range error"); #endif buf = (byte *) SZ_GetSpace (sb, 2); buf[0] = c&0xff; buf[1] = c>>8; } void MSG_WriteLong (sizebuf_t *sb, int c) { byte *buf; buf = (byte *) SZ_GetSpace (sb, 4); buf[0] = c&0xff; buf[1] = (c>>8)&0xff; buf[2] = (c>>16)&0xff; buf[3] = c>>24; } void MSG_WriteFloat (sizebuf_t *sb, float f) { union { float f; int l; } dat; dat.f = f; dat.l = LittleLong (dat.l); SZ_Write (sb, &dat.l, 4); } void MSG_WriteString (sizebuf_t *sb, const char *s) { if (!s) SZ_Write (sb, "", 1); else SZ_Write (sb, s, Q_strlen(s)+1); } //johnfitz -- original behavior, 13.3 fixed point coords, max range +-4096 void MSG_WriteCoord16 (sizebuf_t *sb, float f) { MSG_WriteShort (sb, Q_rint(f*8)); } //johnfitz -- 16.8 fixed point coords, max range +-32768 void MSG_WriteCoord24 (sizebuf_t *sb, float f) { MSG_WriteShort (sb, f); MSG_WriteByte (sb, (int)(f*255)%255); } //johnfitz -- 32-bit float coords void MSG_WriteCoord32f (sizebuf_t *sb, float f) { MSG_WriteFloat (sb, f); } void MSG_WriteCoord (sizebuf_t *sb, float f) { MSG_WriteCoord16 (sb, f); } void MSG_WriteAngle (sizebuf_t *sb, float f) { MSG_WriteByte (sb, Q_rint(f * 256.0 / 360.0) & 255); //johnfitz -- use Q_rint instead of (int) } //johnfitz -- for PROTOCOL_FITZQUAKE void MSG_WriteAngle16 (sizebuf_t *sb, float f) { MSG_WriteShort (sb, Q_rint(f * 65536.0 / 360.0) & 65535); } //johnfitz // // reading functions // int msg_readcount; qboolean msg_badread; void MSG_BeginReading (void) { msg_readcount = 0; msg_badread = false; } // returns -1 and sets msg_badread if no more characters are available int MSG_ReadChar (void) { int c; if (msg_readcount+1 > net_message.cursize) { msg_badread = true; return -1; } c = (signed char)net_message.data[msg_readcount]; msg_readcount++; return c; } int MSG_ReadByte (void) { int c; if (msg_readcount+1 > net_message.cursize) { msg_badread = true; return -1; } c = (unsigned char)net_message.data[msg_readcount]; msg_readcount++; return c; } int MSG_ReadShort (void) { int c; if (msg_readcount+2 > net_message.cursize) { msg_badread = true; return -1; } c = (short)(net_message.data[msg_readcount] + (net_message.data[msg_readcount+1]<<8)); msg_readcount += 2; return c; } int MSG_ReadLong (void) { int c; if (msg_readcount+4 > net_message.cursize) { msg_badread = true; return -1; } c = net_message.data[msg_readcount] + (net_message.data[msg_readcount+1]<<8) + (net_message.data[msg_readcount+2]<<16) + (net_message.data[msg_readcount+3]<<24); msg_readcount += 4; return c; } float MSG_ReadFloat (void) { union { byte b[4]; float f; int l; } dat; dat.b[0] = net_message.data[msg_readcount]; dat.b[1] = net_message.data[msg_readcount+1]; dat.b[2] = net_message.data[msg_readcount+2]; dat.b[3] = net_message.data[msg_readcount+3]; msg_readcount += 4; dat.l = LittleLong (dat.l); return dat.f; } const char *MSG_ReadString (void) { static char string[2048]; int c; size_t l; l = 0; do { c = MSG_ReadByte (); if (c == -1 || c == 0) break; string[l] = c; l++; } while (l < sizeof(string) - 1); string[l] = 0; return string; } //johnfitz -- original behavior, 13.3 fixed point coords, max range +-4096 float MSG_ReadCoord16 (void) { return MSG_ReadShort() * (1.0/8); } //johnfitz -- 16.8 fixed point coords, max range +-32768 float MSG_ReadCoord24 (void) { return MSG_ReadShort() + MSG_ReadByte() * (1.0/255); } //johnfitz -- 32-bit float coords float MSG_ReadCoord32f (void) { return MSG_ReadFloat(); } float MSG_ReadCoord (void) { return MSG_ReadCoord16(); } float MSG_ReadAngle (void) { return MSG_ReadChar() * (360.0/256); } //johnfitz -- for PROTOCOL_FITZQUAKE float MSG_ReadAngle16 (void) { return MSG_ReadShort() * (360.0 / 65536); } //johnfitz //=========================================================================== void SZ_Alloc (sizebuf_t *buf, int startsize) { if (startsize < 256) startsize = 256; buf->data = (byte *) Hunk_AllocName (startsize, "sizebuf"); buf->maxsize = startsize; buf->cursize = 0; } void SZ_Free (sizebuf_t *buf) { // Z_Free (buf->data); // buf->data = NULL; // buf->maxsize = 0; buf->cursize = 0; } void SZ_Clear (sizebuf_t *buf) { buf->cursize = 0; } void *SZ_GetSpace (sizebuf_t *buf, int length) { void *data; if (buf->cursize + length > buf->maxsize) { if (!buf->allowoverflow) Sys_Error ("SZ_GetSpace: overflow without allowoverflow set"); if (length > buf->maxsize) Sys_Error ("SZ_GetSpace: %i is > full buffer size", length); buf->overflowed = true; Con_Printf ("SZ_GetSpace: overflow"); SZ_Clear (buf); } data = buf->data + buf->cursize; buf->cursize += length; return data; } void SZ_Write (sizebuf_t *buf, const void *data, int length) { Q_memcpy (SZ_GetSpace(buf,length),data,length); } void SZ_Print (sizebuf_t *buf, const char *data) { int len = Q_strlen(data) + 1; if (buf->data[buf->cursize-1]) { /* no trailing 0 */ Q_memcpy ((byte *)SZ_GetSpace(buf, len ) , data, len); } else { /* write over trailing 0 */ Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1, data, len); } } //============================================================================ /* ============ COM_SkipPath ============ */ const char *COM_SkipPath (const char *pathname) { const char *last; last = pathname; while (*pathname) { if (*pathname == '/') last = pathname + 1; pathname++; } return last; } /* ============ COM_StripExtension ============ */ void COM_StripExtension (const char *in, char *out, size_t outsize) { int length; if (!*in) { *out = '\0'; return; } if (in != out) /* copy when not in-place editing */ q_strlcpy (out, in, outsize); length = (int)strlen(out) - 1; while (length > 0 && out[length] != '.') { --length; if (out[length] == '/' || out[length] == '\\') return; /* no extension */ } if (length > 0) out[length] = '\0'; } /* ============ COM_FileGetExtension - doesn't return NULL ============ */ const char *COM_FileGetExtension (const char *in) { const char *src; size_t len; len = strlen(in); if (len < 2) /* nothing meaningful */ return ""; src = in + len - 1; while (src != in && src[-1] != '.') src--; if (src == in || strchr(src, '/') != NULL || strchr(src, '\\') != NULL) return ""; /* no extension, or parent directory has a dot */ return src; } /* ============ COM_ExtractExtension ============ */ void COM_ExtractExtension (const char *in, char *out, size_t outsize) { const char *ext = COM_FileGetExtension (in); if (! *ext) *out = '\0'; else q_strlcpy (out, ext, outsize); } /* ============ COM_FileBase take 'somedir/otherdir/filename.ext', write only 'filename' to the output ============ */ void COM_FileBase (const char *in, char *out, size_t outsize) { const char *dot, *slash, *s; s = in; slash = in; dot = NULL; while (*s) { if (*s == '/') slash = s + 1; if (*s == '.') dot = s; s++; } if (dot == NULL) dot = s; if (dot - slash < 2) q_strlcpy (out, "?model?", outsize); else { size_t len = dot - slash; if (len >= outsize) len = outsize - 1; memcpy (out, slash, len); out[len] = '\0'; } } /* ================== COM_DefaultExtension if path doesn't have a .EXT, append extension (extension should include the leading ".") ================== */ #if 0 /* can be dangerous */ void COM_DefaultExtension (char *path, const char *extension, size_t len) { char *src; if (!*path) return; src = path + strlen(path) - 1; while (*src != '/' && *src != '\\' && src != path) { if (*src == '.') return; // it has an extension src--; } q_strlcat(path, extension, len); } #endif /* ================== COM_AddExtension if path extension doesn't match .EXT, append it (extension should include the leading ".") ================== */ void COM_AddExtension (char *path, const char *extension, size_t len) { if (strcmp(COM_FileGetExtension(path), extension + 1) != 0) q_strlcat(path, extension, len); } /* ============== COM_Parse Parse a token out of a string ============== */ const char *COM_Parse (const char *data) { int c; int len; len = 0; com_token[0] = 0; if (!data) return NULL; // skip whitespace skipwhite: while ((c = *data) <= ' ') { if (c == 0) return NULL; // end of file data++; } // skip // comments if (c == '/' && data[1] == '/') { while (*data && *data != '\n') data++; goto skipwhite; } // skip /*..*/ comments if (c == '/' && data[1] == '*') { data += 2; while (*data && !(*data == '*' && data[1] == '/')) data++; if (*data) data += 2; goto skipwhite; } // handle quoted strings specially if (c == '\"') { data++; while (1) { if ((c = *data) != 0) ++data; if (c == '\"' || !c) { com_token[len] = 0; return data; } com_token[len] = c; len++; } } // parse single characters if (c == '{' || c == '}'|| c == '('|| c == ')' || c == '\'' || c == ':') { com_token[len] = c; len++; com_token[len] = 0; return data+1; } // parse a regular word do { com_token[len] = c; data++; len++; c = *data; /* commented out the check for ':' so that ip:port works */ if (c == '{' || c == '}'|| c == '('|| c == ')' || c == '\''/* || c == ':' */) break; } while (c > 32); com_token[len] = 0; return data; } /* ================ COM_CheckParm Returns the position (1 to argc-1) in the program's argument list where the given parameter apears, or 0 if not present ================ */ int COM_CheckParm (const char *parm) { int i; for (i = 1; i < com_argc; i++) { if (!com_argv[i]) continue; // NEXTSTEP sometimes clears appkit vars. if (!Q_strcmp (parm,com_argv[i])) return i; } return 0; } /* ================ COM_CheckRegistered Looks for the pop.txt file and verifies it. Sets the "registered" cvar. Immediately exits out if an alternate game was attempted to be started without being registered. ================ */ static void COM_CheckRegistered (void) { int h; unsigned short check[128]; int i; COM_OpenFile("gfx/pop.lmp", &h, NULL); if (h == -1) { Cvar_SetROM ("registered", "0"); Con_Printf ("Playing shareware version.\n"); if (com_modified) Sys_Error ("You must have the registered version to use modified games"); return; } Sys_FileRead (h, check, sizeof(check)); COM_CloseFile (h); for (i = 0; i < 128; i++) { if (pop[i] != (unsigned short)BigShort (check[i])) Sys_Error ("Corrupted data file."); } for (i = 0; com_cmdline[i]; i++) { if (com_cmdline[i]!= ' ') break; } Cvar_SetROM ("cmdline", &com_cmdline[i]); Cvar_SetROM ("registered", "1"); Con_Printf ("Playing registered version.\n"); } /* ================ COM_InitArgv ================ */ void COM_InitArgv (int argc, char **argv) { int i, j, n; // reconstitute the command line for the cmdline externally visible cvar n = 0; for (j = 0; (j<MAX_NUM_ARGVS) && (j< argc); j++) { i = 0; while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i]) { com_cmdline[n++] = argv[j][i++]; } if (n < (CMDLINE_LENGTH - 1)) com_cmdline[n++] = ' '; else break; } if (n > 0 && com_cmdline[n-1] == ' ') com_cmdline[n-1] = 0; //johnfitz -- kill the trailing space Con_Printf("Command line: %s\n", com_cmdline); for (com_argc = 0; (com_argc < MAX_NUM_ARGVS) && (com_argc < argc); com_argc++) { largv[com_argc] = argv[com_argc]; if (!Q_strcmp ("-safe", argv[com_argc])) safemode = 1; } largv[com_argc] = argvdummy; com_argv = largv; if (COM_CheckParm ("-rogue")) { rogue = true; standard_quake = false; } if (COM_CheckParm ("-hipnotic") || COM_CheckParm ("-quoth")) //johnfitz -- "-quoth" support { hipnotic = true; standard_quake = false; } } /* ================ Test_f -- johnfitz ================ */ #ifdef _DEBUG static void FitzTest_f (void) { } #endif /* ================ COM_Init ================ */ void COM_Init (void) { int i = 0x12345678; /* U N I X */ /* BE_ORDER: 12 34 56 78 U N I X LE_ORDER: 78 56 34 12 X I N U PDP_ORDER: 34 12 78 56 N U X I */ if ( *(char *)&i == 0x12 ) host_bigendian = true; else if ( *(char *)&i == 0x78 ) host_bigendian = false; else /* if ( *(char *)&i == 0x34 ) */ Sys_Error ("Unsupported endianism."); if (host_bigendian) { BigShort = ShortNoSwap; LittleShort = ShortSwap; BigLong = LongNoSwap; LittleLong = LongSwap; BigFloat = FloatNoSwap; LittleFloat = FloatSwap; } else /* assumed LITTLE_ENDIAN. */ { BigShort = ShortSwap; LittleShort = ShortNoSwap; BigLong = LongSwap; LittleLong = LongNoSwap; BigFloat = FloatSwap; LittleFloat = FloatNoSwap; } if (COM_CheckParm("-fitz")) fitzmode = true; #ifdef _DEBUG Cmd_AddCommand ("fitztest", FitzTest_f); //johnfitz #endif } /* ============ va does a varargs printf into a temp buffer. cycles between 4 different static buffers. the number of buffers cycled is defined in VA_NUM_BUFFS. FIXME: make this buffer size safe someday ============ */ #define VA_NUM_BUFFS 4 #define VA_BUFFERLEN 1024 static char *get_va_buffer(void) { static char va_buffers[VA_NUM_BUFFS][VA_BUFFERLEN]; static int buffer_idx = 0; buffer_idx = (buffer_idx + 1) & (VA_NUM_BUFFS - 1); return va_buffers[buffer_idx]; } char *va (const char *format, ...) { va_list argptr; char *va_buf; va_buf = get_va_buffer (); va_start (argptr, format); q_vsnprintf (va_buf, VA_BUFFERLEN, format, argptr); va_end (argptr); return va_buf; } /* ============================================================================= QUAKE FILESYSTEM ============================================================================= */ int com_filesize; // // on-disk pakfile // typedef struct { char name[56]; int filepos, filelen; } dpackfile_t; typedef struct { char id[4]; int dirofs; int dirlen; } dpackheader_t; #define MAX_FILES_IN_PACK 2048 char com_gamedir[MAX_OSPATH]; char com_basedir[MAX_OSPATH]; int file_from_pak; // ZOID: global indicating that file came from a pak searchpath_t *com_searchpaths; searchpath_t *com_base_searchpaths; /* ============ COM_Path_f ============ */ static void COM_Path_f (void) { searchpath_t *s; Con_Printf ("Current search path:\n"); for (s = com_searchpaths; s; s = s->next) { if (s->pack) { Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles); } else Con_Printf ("%s\n", s->filename); } } /* ============ COM_WriteFile The filename will be prefixed by the current game directory ============ */ void COM_WriteFile (const char *filename, const void *data, int len) { int handle; char name[MAX_OSPATH]; Sys_mkdir (com_gamedir); //johnfitz -- if we've switched to a nonexistant gamedir, create it now so we don't crash q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, filename); handle = Sys_FileOpenWrite (name); if (handle == -1) { Sys_Printf ("COM_WriteFile: failed on %s\n", name); return; } Sys_Printf ("COM_WriteFile: %s\n", name); Sys_FileWrite (handle, data, len); Sys_FileClose (handle); } /* ============ COM_CreatePath ============ */ void COM_CreatePath (char *path) { char *ofs; for (ofs = path + 1; *ofs; ofs++) { if (*ofs == '/') { // create the directory *ofs = 0; Sys_mkdir (path); *ofs = '/'; } } } /* ================ COM_filelength ================ */ long COM_filelength (FILE *f) { long pos, end; pos = ftell (f); fseek (f, 0, SEEK_END); end = ftell (f); fseek (f, pos, SEEK_SET); return end; } /* =========== COM_FindFile Finds the file in the search path. Sets com_filesize and one of handle or file If neither of file or handle is set, this can be used for detecting a file's presence. =========== */ static int COM_FindFile (const char *filename, int *handle, FILE **file, unsigned int *path_id) { searchpath_t *search; char netpath[MAX_OSPATH]; pack_t *pak; int i, findtime; if (file && handle) Sys_Error ("COM_FindFile: both handle and file set"); file_from_pak = 0; // // search through the path, one element at a time // for (search = com_searchpaths; search; search = search->next) { if (search->pack) /* look through all the pak file elements */ { pak = search->pack; for (i = 0; i < pak->numfiles; i++) { if (strcmp(pak->files[i].name, filename) != 0) continue; // found it! com_filesize = pak->files[i].filelen; file_from_pak = 1; if (path_id) *path_id = search->path_id; if (handle) { *handle = pak->handle; Sys_FileSeek (pak->handle, pak->files[i].filepos); return com_filesize; } else if (file) { /* open a new file on the pakfile */ *file = fopen (pak->filename, "rb"); if (*file) fseek (*file, pak->files[i].filepos, SEEK_SET); return com_filesize; } else /* for COM_FileExists() */ { return com_filesize; } } } else /* check a file in the directory tree */ { if (!registered.value) { /* if not a registered version, don't ever go beyond base */ if ( strchr (filename, '/') || strchr (filename,'\\')) continue; } q_snprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename); findtime = Sys_FileTime (netpath); if (findtime == -1) continue; if (path_id) *path_id = search->path_id; if (handle) { com_filesize = Sys_FileOpenRead (netpath, &i); *handle = i; return com_filesize; } else if (file) { *file = fopen (netpath, "rb"); com_filesize = (*file == NULL) ? -1 : COM_filelength (*file); return com_filesize; } else { return 0; /* dummy valid value for COM_FileExists() */ } } } if (strcmp(COM_FileGetExtension(filename), "pcx") != 0 && strcmp(COM_FileGetExtension(filename), "tga") != 0 && strcmp(COM_FileGetExtension(filename), "lit") != 0 && strcmp(COM_FileGetExtension(filename), "ent") != 0) Con_DPrintf ("FindFile: can't find %s\n", filename); else Con_DPrintf2("FindFile: can't find %s\n", filename); // Log pcx, tga, lit, ent misses only if (developer.value >= 2) if (handle) *handle = -1; if (file) *file = NULL; com_filesize = -1; return com_filesize; } /* =========== COM_FileExists Returns whether the file is found in the quake filesystem. =========== */ qboolean COM_FileExists (const char *filename, unsigned int *path_id) { int ret = COM_FindFile (filename, NULL, NULL, path_id); return (ret == -1) ? false : true; } /* =========== COM_OpenFile filename never has a leading slash, but may contain directory walks returns a handle and a length it may actually be inside a pak file =========== */ int COM_OpenFile (const char *filename, int *handle, unsigned int *path_id) { return COM_FindFile (filename, handle, NULL, path_id); } /* =========== COM_FOpenFile If the requested file is inside a packfile, a new FILE * will be opened into the file. =========== */ int COM_FOpenFile (const char *filename, FILE **file, unsigned int *path_id) { return COM_FindFile (filename, NULL, file, path_id); } /* ============ COM_CloseFile If it is a pak file handle, don't really close it ============ */ void COM_CloseFile (int h) { searchpath_t *s; for (s = com_searchpaths; s; s = s->next) if (s->pack && s->pack->handle == h) return; Sys_FileClose (h); } /* ============ COM_LoadFile Filename are reletive to the quake directory. Allways appends a 0 byte. ============ */ #define LOADFILE_ZONE 0 #define LOADFILE_HUNK 1 #define LOADFILE_TEMPHUNK 2 #define LOADFILE_CACHE 3 #define LOADFILE_STACK 4 #define LOADFILE_MALLOC 5 static byte *loadbuf; static cache_user_t *loadcache; static int loadsize; byte *COM_LoadFile (const char *path, int usehunk, unsigned int *path_id) { int h; byte *buf; char base[32]; int len; buf = NULL; // quiet compiler warning // look for it in the filesystem or pack files len = COM_OpenFile (path, &h, path_id); if (h == -1) return NULL; // extract the filename base name for hunk tag COM_FileBase (path, base, sizeof(base)); switch (usehunk) { case LOADFILE_HUNK: buf = (byte *) Hunk_AllocName (len+1, base); break; case LOADFILE_TEMPHUNK: buf = (byte *) Hunk_TempAlloc (len+1); break; case LOADFILE_ZONE: buf = (byte *) Z_Malloc (len+1); break; case LOADFILE_CACHE: buf = (byte *) Cache_Alloc (loadcache, len+1, base); break; case LOADFILE_STACK: if (len < loadsize) buf = loadbuf; else buf = (byte *) Hunk_TempAlloc (len+1); break; case LOADFILE_MALLOC: buf = (byte *) malloc (len+1); break; default: Sys_Error ("COM_LoadFile: bad usehunk"); } if (!buf) Sys_Error ("COM_LoadFile: not enough space for %s", path); ((byte *)buf)[len] = 0; Sys_FileRead (h, buf, len); COM_CloseFile (h); return buf; } byte *COM_LoadHunkFile (const char *path, unsigned int *path_id) { return COM_LoadFile (path, LOADFILE_HUNK, path_id); } byte *COM_LoadZoneFile (const char *path, unsigned int *path_id) { return COM_LoadFile (path, LOADFILE_ZONE, path_id); } byte *COM_LoadTempFile (const char *path, unsigned int *path_id) { return COM_LoadFile (path, LOADFILE_TEMPHUNK, path_id); } void COM_LoadCacheFile (const char *path, struct cache_user_s *cu, unsigned int *path_id) { loadcache = cu; COM_LoadFile (path, LOADFILE_CACHE, path_id); } // uses temp hunk if larger than bufsize byte *COM_LoadStackFile (const char *path, void *buffer, int bufsize, unsigned int *path_id) { byte *buf; loadbuf = (byte *)buffer; loadsize = bufsize; buf = COM_LoadFile (path, LOADFILE_STACK, path_id); return buf; } // returns malloc'd memory byte *COM_LoadMallocFile (const char *path, unsigned int *path_id) { return COM_LoadFile (path, LOADFILE_MALLOC, path_id); } /* ================= COM_LoadPackFile -- johnfitz -- modified based on topaz's tutorial Takes an explicit (not game tree related) path to a pak file. Loads the header and directory, adding the files at the beginning of the list so they override previous pack files. ================= */ static pack_t *COM_LoadPackFile (const char *packfile) { dpackheader_t header; int i; packfile_t *newfiles; int numpackfiles; pack_t *pack; int packhandle; dpackfile_t info[MAX_FILES_IN_PACK]; unsigned short crc; if (Sys_FileOpenRead (packfile, &packhandle) == -1) return NULL; Sys_FileRead (packhandle, (void *)&header, sizeof(header)); if (header.id[0] != 'P' || header.id[1] != 'A' || header.id[2] != 'C' || header.id[3] != 'K') Sys_Error ("%s is not a packfile", packfile); header.dirofs = LittleLong (header.dirofs); header.dirlen = LittleLong (header.dirlen); numpackfiles = header.dirlen / sizeof(dpackfile_t); if (header.dirlen < 0 || header.dirofs < 0) { Sys_Error ("Invalid packfile %s (dirlen: %i, dirofs: %i)", packfile, header.dirlen, header.dirofs); } if (!numpackfiles) { Sys_Printf ("WARNING: %s has no files, ignored\n", packfile); Sys_FileClose (packhandle); return NULL; } if (numpackfiles > MAX_FILES_IN_PACK) Sys_Error ("%s has %i files", packfile, numpackfiles); if (numpackfiles != PAK0_COUNT) com_modified = true; // not the original file newfiles = (packfile_t *) Z_Malloc(numpackfiles * sizeof(packfile_t)); Sys_FileSeek (packhandle, header.dirofs); Sys_FileRead (packhandle, (void *)info, header.dirlen); // crc the directory to check for modifications CRC_Init (&crc); for (i = 0; i < header.dirlen; i++) CRC_ProcessByte (&crc, ((byte *)info)[i]); if (crc != PAK0_CRC_V106 && crc != PAK0_CRC_V101 && crc != PAK0_CRC_V100) com_modified = true; // parse the directory for (i = 0; i < numpackfiles; i++) { q_strlcpy (newfiles[i].name, info[i].name, sizeof(newfiles[i].name)); newfiles[i].filepos = LittleLong(info[i].filepos); newfiles[i].filelen = LittleLong(info[i].filelen); } pack = (pack_t *) Z_Malloc (sizeof (pack_t)); q_strlcpy (pack->filename, packfile, sizeof(pack->filename)); pack->handle = packhandle; pack->numfiles = numpackfiles; pack->files = newfiles; //Sys_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles); return pack; } /* ================= COM_AddGameDirectory -- johnfitz -- modified based on topaz's tutorial ================= */ static void COM_AddGameDirectory (const char *base, const char *dir) { int i; unsigned int path_id; searchpath_t *search; pack_t *pak, *qspak; char pakfile[MAX_OSPATH]; qboolean been_here = false; q_strlcpy (com_gamedir, va("%s/%s", base, dir), sizeof(com_gamedir)); // assign a path_id to this game directory if (com_searchpaths) path_id = com_searchpaths->path_id << 1; else path_id = 1U; _add_path: // add the directory to the search path search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t)); search->path_id = path_id; q_strlcpy (search->filename, com_gamedir, sizeof(search->filename)); search->next = com_searchpaths; com_searchpaths = search; // add any pak files in the format pak0.pak pak1.pak, ... for (i = 0; ; i++) { q_snprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", com_gamedir, i); pak = COM_LoadPackFile (pakfile); if (i != 0 || path_id != 1 || fitzmode) qspak = NULL; else { qboolean old = com_modified; if (been_here) base = host_parms->userdir; q_snprintf (pakfile, sizeof(pakfile), "%s/quakespasm.pak", base); qspak = COM_LoadPackFile (pakfile); com_modified = old; } if (pak) { search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t)); search->path_id = path_id; search->pack = pak; search->next = com_searchpaths; com_searchpaths = search; } if (qspak) { search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t)); search->path_id = path_id; search->pack = qspak; search->next = com_searchpaths; com_searchpaths = search; } if (!pak) break; } if (!been_here && host_parms->userdir != host_parms->basedir) { been_here = true; q_strlcpy(com_gamedir, va("%s/%s", host_parms->userdir, dir), sizeof(com_gamedir)); Sys_mkdir(com_gamedir); goto _add_path; } } //============================================================================== //johnfitz -- dynamic gamedir stuff -- modified by QuakeSpasm team. //============================================================================== void ExtraMaps_NewGame (void); static void COM_Game_f (void) { if (Cmd_Argc() > 1) { const char *p = Cmd_Argv(1); const char *p2 = Cmd_Argv(2); searchpath_t *search; if (!registered.value) //disable shareware quake { Con_Printf("You must have the registered version to use modified games\n"); return; } if (!*p || !strcmp(p, ".") || strstr(p, "..") || strstr(p, "/") || strstr(p, "\\") || strstr(p, ":")) { Con_Printf ("gamedir should be a single directory name, not a path\n"); return; } if (*p2) { if (strcmp(p2,"-hipnotic") && strcmp(p2,"-rogue") && strcmp(p2,"-quoth")) { Con_Printf ("invalid mission pack argument to \"game\"\n"); return; } if (!q_strcasecmp(p, GAMENAME)) { Con_Printf ("no mission pack arguments to %s game\n", GAMENAME); return; } } if (!q_strcasecmp(p, COM_SkipPath(com_gamedir))) //no change { if (com_searchpaths->path_id > 1) { //current game not id1 if (*p2 && com_searchpaths->path_id == 2) { // rely on QuakeSpasm extension treating '-game missionpack' // as '-missionpack', otherwise would be a mess if (!q_strcasecmp(p, &p2[1])) goto _same; Con_Printf("reloading game \"%s\" with \"%s\" support\n", p, &p2[1]); } else if (!*p2 && com_searchpaths->path_id > 2) Con_Printf("reloading game \"%s\" without mission pack support\n", p); else goto _same; } else { _same: Con_Printf("\"game\" is already \"%s\"\n", COM_SkipPath(com_gamedir)); return; } } com_modified = true; //Kill the server CL_Disconnect (); Host_ShutdownServer(true); //Write config file Host_WriteConfiguration (); //Kill the extra game if it is loaded while (com_searchpaths != com_base_searchpaths) { if (com_searchpaths->pack) { Sys_FileClose (com_searchpaths->pack->handle); Z_Free (com_searchpaths->pack->files); Z_Free (com_searchpaths->pack); } search = com_searchpaths->next; Z_Free (com_searchpaths); com_searchpaths = search; } hipnotic = false; rogue = false; standard_quake = true; if (q_strcasecmp(p, GAMENAME)) //game is not id1 { if (*p2) { COM_AddGameDirectory (com_basedir, &p2[1]); standard_quake = false; if (!strcmp(p2,"-hipnotic") || !strcmp(p2,"-quoth")) hipnotic = true; else if (!strcmp(p2,"-rogue")) rogue = true; if (q_strcasecmp(p, &p2[1])) //don't load twice COM_AddGameDirectory (com_basedir, p); } else { COM_AddGameDirectory (com_basedir, p); // QuakeSpasm extension: treat '-game missionpack' as '-missionpack' if (!q_strcasecmp(p,"hipnotic") || !q_strcasecmp(p,"quoth")) { hipnotic = true; standard_quake = false; } else if (!q_strcasecmp(p,"rogue")) { rogue = true; standard_quake = false; } } } else // just update com_gamedir { q_snprintf (com_gamedir, sizeof(com_gamedir), "%s/%s", (host_parms->userdir != host_parms->basedir)? host_parms->userdir : com_basedir, GAMENAME); } //clear out and reload appropriate data Cache_Flush (); Mod_ResetAll(); if (!isDedicated) { TexMgr_NewGame (); Draw_NewGame (); R_NewGame (); } ExtraMaps_NewGame (); DemoList_Rebuild (); Con_Printf("\"game\" changed to \"%s\"\n", COM_SkipPath(com_gamedir)); Con_Printf("enter \"exec quake.rc\" to load new configs\n"); //Cbuf_InsertText ("exec quake.rc\n"); } else //Diplay the current gamedir Con_Printf("\"game\" is \"%s\"\n", COM_SkipPath(com_gamedir)); } /* ================= COM_InitFilesystem ================= */ void COM_InitFilesystem (void) //johnfitz -- modified based on topaz's tutorial { int i, j; Cvar_RegisterVariable (®istered); Cvar_RegisterVariable (&cmdline); Cmd_AddCommand ("path", COM_Path_f); Cmd_AddCommand ("game", COM_Game_f); //johnfitz i = COM_CheckParm ("-basedir"); if (i && i < com_argc-1) q_strlcpy (com_basedir, com_argv[i + 1], sizeof(com_basedir)); else q_strlcpy (com_basedir, host_parms->basedir, sizeof(com_basedir)); j = strlen (com_basedir); if (j < 1) Sys_Error("Bad argument to -basedir"); if ((com_basedir[j-1] == '\\') || (com_basedir[j-1] == '/')) com_basedir[j-1] = 0; // start up with GAMENAME by default (id1) COM_AddGameDirectory (com_basedir, GAMENAME); /* this is the end of our base searchpath: * any set gamedirs, such as those from -game command line * arguments or by the 'game' console command will be freed * up to here upon a new game command. */ com_base_searchpaths = com_searchpaths; // add mission pack requests (only one should be specified) if (COM_CheckParm ("-rogue")) COM_AddGameDirectory (com_basedir, "rogue"); if (COM_CheckParm ("-hipnotic")) COM_AddGameDirectory (com_basedir, "hipnotic"); if (COM_CheckParm ("-quoth")) COM_AddGameDirectory (com_basedir, "quoth"); i = COM_CheckParm ("-game"); if (i && i < com_argc-1) { const char *p = com_argv[i + 1]; if (!*p || !strcmp(p, ".") || strstr(p, "..") || strstr(p, "/") || strstr(p, "\\") || strstr(p, ":")) Sys_Error ("gamedir should be a single directory name, not a path\n"); com_modified = true; // don't load mission packs twice if (COM_CheckParm ("-rogue") && !q_strcasecmp(p, "rogue")) p = NULL; if (COM_CheckParm ("-hipnotic") && !q_strcasecmp(p, "hipnotic")) p = NULL; if (COM_CheckParm ("-quoth") && !q_strcasecmp(p, "quoth")) p = NULL; if (p != NULL) { COM_AddGameDirectory (com_basedir, p); // QuakeSpasm extension: treat '-game missionpack' as '-missionpack' if (!q_strcasecmp(p,"rogue")) { rogue = true; standard_quake = false; } if (!q_strcasecmp(p,"hipnotic") || !q_strcasecmp(p,"quoth")) { hipnotic = true; standard_quake = false; } } } COM_CheckRegistered (); } /* The following FS_*() stdio replacements are necessary if one is * to perform non-sequential reads on files reopened on pak files * because we need the bookkeeping about file start/end positions. * Allocating and filling in the fshandle_t structure is the users' * responsibility when the file is initially opened. */ size_t FS_fread(void *ptr, size_t size, size_t nmemb, fshandle_t *fh) { long byte_size; long bytes_read; size_t nmemb_read; if (!fh) { errno = EBADF; return 0; } if (!ptr) { errno = EFAULT; return 0; } if (!size || !nmemb) { /* no error, just zero bytes wanted */ errno = 0; return 0; } byte_size = nmemb * size; if (byte_size > fh->length - fh->pos) /* just read to end */ byte_size = fh->length - fh->pos; bytes_read = fread(ptr, 1, byte_size, fh->file); fh->pos += bytes_read; /* fread() must return the number of elements read, * not the total number of bytes. */ nmemb_read = bytes_read / size; /* even if the last member is only read partially * it is counted as a whole in the return value. */ if (bytes_read % size) nmemb_read++; return nmemb_read; } int FS_fseek(fshandle_t *fh, long offset, int whence) { /* I don't care about 64 bit off_t or fseeko() here. * the quake/hexen2 file system is 32 bits, anyway. */ int ret; if (!fh) { errno = EBADF; return -1; } /* the relative file position shouldn't be smaller * than zero or bigger than the filesize. */ switch (whence) { case SEEK_SET: break; case SEEK_CUR: offset += fh->pos; break; case SEEK_END: offset = fh->length + offset; break; default: errno = EINVAL; return -1; } if (offset < 0) { errno = EINVAL; return -1; } if (offset > fh->length) /* just seek to end */ offset = fh->length; ret = fseek(fh->file, fh->start + offset, SEEK_SET); if (ret < 0) return ret; fh->pos = offset; return 0; } int FS_fclose(fshandle_t *fh) { if (!fh) { errno = EBADF; return -1; } return fclose(fh->file); } long FS_ftell(fshandle_t *fh) { if (!fh) { errno = EBADF; return -1; } return fh->pos; } void FS_rewind(fshandle_t *fh) { if (!fh) return; clearerr(fh->file); fseek(fh->file, fh->start, SEEK_SET); fh->pos = 0; } int FS_feof(fshandle_t *fh) { if (!fh) { errno = EBADF; return -1; } if (fh->pos >= fh->length) return -1; return 0; } int FS_ferror(fshandle_t *fh) { if (!fh) { errno = EBADF; return -1; } return ferror(fh->file); } int FS_fgetc(fshandle_t *fh) { if (!fh) { errno = EBADF; return EOF; } if (fh->pos >= fh->length) return EOF; fh->pos += 1; return fgetc(fh->file); } char *FS_fgets(char *s, int size, fshandle_t *fh) { char *ret; if (FS_feof(fh)) return NULL; if (size > (fh->length - fh->pos) + 1) size = (fh->length - fh->pos) + 1; ret = fgets(s, size, fh->file); fh->pos = ftell(fh->file) - fh->start; return ret; } long FS_filelength (fshandle_t *fh) { if (!fh) { errno = EBADF; return -1; } return fh->length; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/wad.c�����������������������������������������������������������������������0000644�0000000�0000000�00000007333�12407762022�014446� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // wad.c #include "quakedef.h" int wad_numlumps; lumpinfo_t *wad_lumps; byte *wad_base = NULL; void SwapPic (qpic_t *pic); /* ================== W_CleanupName Lowercases name and pads with spaces and a terminating 0 to the length of lumpinfo_t->name. Used so lumpname lookups can proceed rapidly by comparing 4 chars at a time Space padding is so names can be printed nicely in tables. Can safely be performed in place. ================== */ void W_CleanupName (const char *in, char *out) { int i; int c; for (i=0 ; i<16 ; i++ ) { c = in[i]; if (!c) break; if (c >= 'A' && c <= 'Z') c += ('a' - 'A'); out[i] = c; } for ( ; i< 16 ; i++ ) out[i] = 0; } /* ==================== W_LoadWadFile ==================== */ void W_LoadWadFile (void) //johnfitz -- filename is now hard-coded for honesty { lumpinfo_t *lump_p; wadinfo_t *header; int i; int infotableofs; const char *filename = WADFILENAME; //johnfitz -- modified to use malloc //TODO: use cache_alloc if (wad_base) free (wad_base); wad_base = COM_LoadMallocFile (filename, NULL); if (!wad_base) Sys_Error ("W_LoadWadFile: couldn't load %s", filename); header = (wadinfo_t *)wad_base; if (header->identification[0] != 'W' || header->identification[1] != 'A' || header->identification[2] != 'D' || header->identification[3] != '2') Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename); wad_numlumps = LittleLong(header->numlumps); infotableofs = LittleLong(header->infotableofs); wad_lumps = (lumpinfo_t *)(wad_base + infotableofs); for (i=0, lump_p = wad_lumps ; i<wad_numlumps ; i++,lump_p++) { lump_p->filepos = LittleLong(lump_p->filepos); lump_p->size = LittleLong(lump_p->size); W_CleanupName (lump_p->name, lump_p->name); // CAUTION: in-place editing!!! if (lump_p->type == TYP_QPIC) SwapPic ( (qpic_t *)(wad_base + lump_p->filepos)); } } /* ============= W_GetLumpinfo ============= */ lumpinfo_t *W_GetLumpinfo (const char *name) { int i; lumpinfo_t *lump_p; char clean[16]; W_CleanupName (name, clean); for (lump_p=wad_lumps, i=0 ; i<wad_numlumps ; i++,lump_p++) { if (!strcmp(clean, lump_p->name)) return lump_p; } Con_SafePrintf ("W_GetLumpinfo: %s not found\n", name); //johnfitz -- was Sys_Error return NULL; } void *W_GetLumpName (const char *name) { lumpinfo_t *lump; lump = W_GetLumpinfo (name); if (!lump) return NULL; //johnfitz return (void *)(wad_base + lump->filepos); } void *W_GetLumpNum (int num) { lumpinfo_t *lump; if (num < 0 || num > wad_numlumps) Sys_Error ("W_GetLumpNum: bad number: %i", num); lump = wad_lumps + num; return (void *)(wad_base + lump->filepos); } /* ============================================================================= automatic byte swapping ============================================================================= */ void SwapPic (qpic_t *pic) { pic->width = LittleLong(pic->width); pic->height = LittleLong(pic->height); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quake/gl_texmgr.c�����������������������������������������������������������������0000644�0000000�0000000�00000111025�12644413102�015650� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2007-2008 Kristian Duske Copyright (C) 2010-2014 QuakeSpasm developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //gl_texmgr.c -- fitzquake's texture manager. manages opengl texture images #include "quakedef.h" const int gl_solid_format = 3; const int gl_alpha_format = 4; static cvar_t gl_texturemode = {"gl_texturemode", "", CVAR_ARCHIVE}; static cvar_t gl_texture_anisotropy = {"gl_texture_anisotropy", "1", CVAR_ARCHIVE}; static cvar_t gl_max_size = {"gl_max_size", "0", CVAR_NONE}; static cvar_t gl_picmip = {"gl_picmip", "0", CVAR_NONE}; static GLint gl_hardware_maxsize; #define MAX_GLTEXTURES 2048 static int numgltextures; static gltexture_t *active_gltextures, *free_gltextures; gltexture_t *notexture, *nulltexture; unsigned int d_8to24table[256]; unsigned int d_8to24table_fbright[256]; unsigned int d_8to24table_fbright_fence[256]; unsigned int d_8to24table_nobright[256]; unsigned int d_8to24table_nobright_fence[256]; unsigned int d_8to24table_conchars[256]; unsigned int d_8to24table_shirt[256]; unsigned int d_8to24table_pants[256]; /* ================================================================================ COMMANDS ================================================================================ */ typedef struct { int magfilter; int minfilter; const char *name; } glmode_t; static glmode_t glmodes[] = { {GL_NEAREST, GL_NEAREST, "GL_NEAREST"}, {GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, "GL_NEAREST_MIPMAP_NEAREST"}, {GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR, "GL_NEAREST_MIPMAP_LINEAR"}, {GL_LINEAR, GL_LINEAR, "GL_LINEAR"}, {GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, "GL_LINEAR_MIPMAP_NEAREST"}, {GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, "GL_LINEAR_MIPMAP_LINEAR"}, }; #define NUM_GLMODES (int)(sizeof(glmodes)/sizeof(glmodes[0])) static int glmode_idx = NUM_GLMODES - 1; /* trilinear */ /* =============== TexMgr_DescribeTextureModes_f -- report available texturemodes =============== */ static void TexMgr_DescribeTextureModes_f (void) { int i; for (i = 0; i < NUM_GLMODES; i++) Con_SafePrintf (" %2i: %s\n", i + 1, glmodes[i].name); Con_Printf ("%i modes\n", i); } /* =============== TexMgr_SetFilterModes =============== */ static void TexMgr_SetFilterModes (gltexture_t *glt) { GL_Bind (glt); if (glt->flags & TEXPREF_NEAREST) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } else if (glt->flags & TEXPREF_LINEAR) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } else if (glt->flags & TEXPREF_MIPMAP) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glmodes[glmode_idx].magfilter); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmodes[glmode_idx].minfilter); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy.value); } else { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glmodes[glmode_idx].magfilter); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmodes[glmode_idx].magfilter); } } /* =============== TexMgr_TextureMode_f -- called when gl_texturemode changes =============== */ static void TexMgr_TextureMode_f (cvar_t *var) { gltexture_t *glt; int i; for (i = 0; i < NUM_GLMODES; i++) { if (!Q_strcmp (glmodes[i].name, gl_texturemode.string)) { if (glmode_idx != i) { glmode_idx = i; for (glt = active_gltextures; glt; glt = glt->next) TexMgr_SetFilterModes (glt); Sbar_Changed (); //sbar graphics need to be redrawn with new filter mode //FIXME: warpimages need to be redrawn, too. } return; } } for (i = 0; i < NUM_GLMODES; i++) { if (!q_strcasecmp (glmodes[i].name, gl_texturemode.string)) { Cvar_SetQuick (&gl_texturemode, glmodes[i].name); return; } } i = atoi(gl_texturemode.string); if (i >= 1 && i <= NUM_GLMODES) { Cvar_SetQuick (&gl_texturemode, glmodes[i-1].name); return; } Con_Printf ("\"%s\" is not a valid texturemode\n", gl_texturemode.string); Cvar_SetQuick (&gl_texturemode, glmodes[glmode_idx].name); } /* =============== TexMgr_Anisotropy_f -- called when gl_texture_anisotropy changes =============== */ static void TexMgr_Anisotropy_f (cvar_t *var) { if (gl_texture_anisotropy.value < 1) { Cvar_SetQuick (&gl_texture_anisotropy, "1"); } else if (gl_texture_anisotropy.value > gl_max_anisotropy) { Cvar_SetValueQuick (&gl_texture_anisotropy, gl_max_anisotropy); } else { gltexture_t *glt; for (glt = active_gltextures; glt; glt = glt->next) { /* TexMgr_SetFilterModes (glt);*/ if (glt->flags & TEXPREF_MIPMAP) { GL_Bind (glt); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glmodes[glmode_idx].magfilter); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmodes[glmode_idx].minfilter); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy.value); } } } } /* =============== TexMgr_Imagelist_f -- report loaded textures =============== */ static void TexMgr_Imagelist_f (void) { float mb; float texels = 0; gltexture_t *glt; for (glt = active_gltextures; glt; glt = glt->next) { Con_SafePrintf (" %4i x%4i %s\n", glt->width, glt->height, glt->name); if (glt->flags & TEXPREF_MIPMAP) texels += glt->width * glt->height * 4.0f / 3.0f; else texels += (glt->width * glt->height); } mb = texels * (Cvar_VariableValue("vid_bpp") / 8.0f) / 0x100000; Con_Printf ("%i textures %i pixels %1.1f megabytes\n", numgltextures, (int)texels, mb); } /* =============== TexMgr_Imagedump_f -- dump all current textures to TGA files =============== */ static void TexMgr_Imagedump_f (void) { char tganame[MAX_OSPATH], tempname[MAX_OSPATH], dirname[MAX_OSPATH]; gltexture_t *glt; byte *buffer; char *c; //create directory q_snprintf(dirname, sizeof(dirname), "%s/imagedump", com_gamedir); Sys_mkdir (dirname); //loop through textures for (glt = active_gltextures; glt; glt = glt->next) { q_strlcpy (tempname, glt->name, sizeof(tempname)); while ( (c = strchr(tempname, ':')) ) *c = '_'; while ( (c = strchr(tempname, '/')) ) *c = '_'; while ( (c = strchr(tempname, '*')) ) *c = '_'; q_snprintf(tganame, sizeof(tganame), "imagedump/%s.tga", tempname); GL_Bind (glt); if (glt->flags & TEXPREF_ALPHA) { buffer = (byte *) malloc(glt->width*glt->height*4); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); Image_WriteTGA (tganame, buffer, glt->width, glt->height, 32, true); } else { buffer = (byte *) malloc(glt->width*glt->height*3); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer); Image_WriteTGA (tganame, buffer, glt->width, glt->height, 24, true); } free (buffer); } Con_Printf ("dumped %i textures to %s\n", numgltextures, dirname); } /* =============== TexMgr_FrameUsage -- report texture memory usage for this frame =============== */ float TexMgr_FrameUsage (void) { float mb; float texels = 0; gltexture_t *glt; for (glt = active_gltextures; glt; glt = glt->next) { if (glt->visframe == r_framecount) { if (glt->flags & TEXPREF_MIPMAP) texels += glt->width * glt->height * 4.0f / 3.0f; else texels += (glt->width * glt->height); } } mb = texels * (Cvar_VariableValue("vid_bpp") / 8.0f) / 0x100000; return mb; } /* ================================================================================ TEXTURE MANAGER ================================================================================ */ /* ================ TexMgr_FindTexture ================ */ gltexture_t *TexMgr_FindTexture (qmodel_t *owner, const char *name) { gltexture_t *glt; if (name) { for (glt = active_gltextures; glt; glt = glt->next) { if (glt->owner == owner && !strcmp (glt->name, name)) return glt; } } return NULL; } /* ================ TexMgr_NewTexture ================ */ gltexture_t *TexMgr_NewTexture (void) { gltexture_t *glt; if (numgltextures == MAX_GLTEXTURES) Sys_Error("numgltextures == MAX_GLTEXTURES\n"); glt = free_gltextures; free_gltextures = glt->next; glt->next = active_gltextures; active_gltextures = glt; glGenTextures(1, &glt->texnum); numgltextures++; return glt; } static void GL_DeleteTexture (gltexture_t *texture); //ericw -- workaround for preventing TexMgr_FreeTexture during TexMgr_ReloadImages static qboolean in_reload_images; /* ================ TexMgr_FreeTexture ================ */ void TexMgr_FreeTexture (gltexture_t *kill) { gltexture_t *glt; if (in_reload_images) return; if (kill == NULL) { Con_Printf ("TexMgr_FreeTexture: NULL texture\n"); return; } if (active_gltextures == kill) { active_gltextures = kill->next; kill->next = free_gltextures; free_gltextures = kill; GL_DeleteTexture(kill); numgltextures--; return; } for (glt = active_gltextures; glt; glt = glt->next) { if (glt->next == kill) { glt->next = kill->next; kill->next = free_gltextures; free_gltextures = kill; GL_DeleteTexture(kill); numgltextures--; return; } } Con_Printf ("TexMgr_FreeTexture: not found\n"); } /* ================ TexMgr_FreeTextures compares each bit in "flags" to the one in glt->flags only if that bit is active in "mask" ================ */ void TexMgr_FreeTextures (unsigned int flags, unsigned int mask) { gltexture_t *glt, *next; for (glt = active_gltextures; glt; glt = next) { next = glt->next; if ((glt->flags & mask) == (flags & mask)) TexMgr_FreeTexture (glt); } } /* ================ TexMgr_FreeTexturesForOwner ================ */ void TexMgr_FreeTexturesForOwner (qmodel_t *owner) { gltexture_t *glt, *next; for (glt = active_gltextures; glt; glt = next) { next = glt->next; if (glt && glt->owner == owner) TexMgr_FreeTexture (glt); } } /* ================ TexMgr_DeleteTextureObjects ================ */ void TexMgr_DeleteTextureObjects (void) { gltexture_t *glt; for (glt = active_gltextures; glt; glt = glt->next) { GL_DeleteTexture (glt); } } /* ================================================================================ INIT ================================================================================ */ /* ================= TexMgr_LoadPalette -- johnfitz -- was VID_SetPalette, moved here, renamed, rewritten ================= */ void TexMgr_LoadPalette (void) { byte *pal, *src, *dst; int i, mark; FILE *f; COM_FOpenFile ("gfx/palette.lmp", &f, NULL); if (!f) Sys_Error ("Couldn't load gfx/palette.lmp"); mark = Hunk_LowMark (); pal = (byte *) Hunk_Alloc (768); fread (pal, 1, 768, f); fclose(f); //standard palette, 255 is transparent dst = (byte *)d_8to24table; src = pal; for (i = 0; i < 256; i++) { *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = 255; } ((byte *) &d_8to24table[255]) [3] = 0; //fullbright palette, 0-223 are black (for additive blending) src = pal + 224*3; dst = (byte *) &d_8to24table_fbright[224]; for (i = 224; i < 256; i++) { *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = 255; } for (i = 0; i < 224; i++) { dst = (byte *) &d_8to24table_fbright[i]; dst[3] = 255; dst[2] = dst[1] = dst[0] = 0; } //nobright palette, 224-255 are black (for additive blending) dst = (byte *)d_8to24table_nobright; src = pal; for (i = 0; i < 256; i++) { *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = 255; } for (i = 224; i < 256; i++) { dst = (byte *) &d_8to24table_nobright[i]; dst[3] = 255; dst[2] = dst[1] = dst[0] = 0; } //fullbright palette, for fence textures memcpy(d_8to24table_fbright_fence, d_8to24table_fbright, 256*4); d_8to24table_fbright_fence[255] = 0; // Alpha of zero. //nobright palette, for fence textures memcpy(d_8to24table_nobright_fence, d_8to24table_nobright, 256*4); d_8to24table_nobright_fence[255] = 0; // Alpha of zero. //conchars palette, 0 and 255 are transparent memcpy(d_8to24table_conchars, d_8to24table, 256*4); ((byte *) &d_8to24table_conchars[0]) [3] = 0; Hunk_FreeToLowMark (mark); } /* ================ TexMgr_NewGame ================ */ void TexMgr_NewGame (void) { TexMgr_FreeTextures (0, TEXPREF_PERSIST); //deletes all textures where TEXPREF_PERSIST is unset TexMgr_LoadPalette (); } /* ============= TexMgr_RecalcWarpImageSize -- called during init, and after a vid_restart choose safe warpimage size and resize existing warpimage textures ============= */ void TexMgr_RecalcWarpImageSize (void) { int mark, oldsize; gltexture_t *glt; byte *dummy; // // find the new correct size // oldsize = gl_warpimagesize; gl_warpimagesize = TexMgr_SafeTextureSize (512); while (gl_warpimagesize > vid.width) gl_warpimagesize >>= 1; while (gl_warpimagesize > vid.height) gl_warpimagesize >>= 1; // ericw -- removed early exit if (gl_warpimagesize == oldsize). // after vid_restart TexMgr_ReloadImage reloads textures // to tx->source_width/source_height, which might not match oldsize. // fixes: https://sourceforge.net/p/quakespasm/bugs/13/ // // resize the textures in opengl // mark = Hunk_LowMark(); dummy = (byte *) Hunk_Alloc (gl_warpimagesize*gl_warpimagesize*4); for (glt = active_gltextures; glt; glt = glt->next) { if (glt->flags & TEXPREF_WARPIMAGE) { GL_Bind (glt); glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, gl_warpimagesize, gl_warpimagesize, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummy); glt->width = glt->height = gl_warpimagesize; } } Hunk_FreeToLowMark (mark); } /* ================ TexMgr_Init must be called before any texture loading ================ */ void TexMgr_Init (void) { int i; static byte notexture_data[16] = {159,91,83,255,0,0,0,255,0,0,0,255,159,91,83,255}; //black and pink checker static byte nulltexture_data[16] = {127,191,255,255,0,0,0,255,0,0,0,255,127,191,255,255}; //black and blue checker extern texture_t *r_notexture_mip, *r_notexture_mip2; // init texture list free_gltextures = (gltexture_t *) Hunk_AllocName (MAX_GLTEXTURES * sizeof(gltexture_t), "gltextures"); active_gltextures = NULL; for (i = 0; i < MAX_GLTEXTURES - 1; i++) free_gltextures[i].next = &free_gltextures[i+1]; free_gltextures[i].next = NULL; numgltextures = 0; // palette TexMgr_LoadPalette (); Cvar_RegisterVariable (&gl_max_size); Cvar_RegisterVariable (&gl_picmip); Cvar_RegisterVariable (&gl_texture_anisotropy); Cvar_SetCallback (&gl_texture_anisotropy, &TexMgr_Anisotropy_f); gl_texturemode.string = glmodes[glmode_idx].name; Cvar_RegisterVariable (&gl_texturemode); Cvar_SetCallback (&gl_texturemode, &TexMgr_TextureMode_f); Cmd_AddCommand ("gl_describetexturemodes", &TexMgr_DescribeTextureModes_f); Cmd_AddCommand ("imagelist", &TexMgr_Imagelist_f); Cmd_AddCommand ("imagedump", &TexMgr_Imagedump_f); // poll max size from hardware glGetIntegerv (GL_MAX_TEXTURE_SIZE, &gl_hardware_maxsize); // load notexture images notexture = TexMgr_LoadImage (NULL, "notexture", 2, 2, SRC_RGBA, notexture_data, "", (src_offset_t)notexture_data, TEXPREF_NEAREST | TEXPREF_PERSIST | TEXPREF_NOPICMIP); nulltexture = TexMgr_LoadImage (NULL, "nulltexture", 2, 2, SRC_RGBA, nulltexture_data, "", (src_offset_t)nulltexture_data, TEXPREF_NEAREST | TEXPREF_PERSIST | TEXPREF_NOPICMIP); //have to assign these here becuase Mod_Init is called before TexMgr_Init r_notexture_mip->gltexture = r_notexture_mip2->gltexture = notexture; //set safe size for warpimages gl_warpimagesize = 0; TexMgr_RecalcWarpImageSize (); } /* ================================================================================ IMAGE LOADING ================================================================================ */ /* ================ TexMgr_Pad -- return smallest power of two greater than or equal to s ================ */ int TexMgr_Pad (int s) { int i; for (i = 1; i < s; i<<=1) ; return i; } /* =============== TexMgr_SafeTextureSize -- return a size with hardware and user prefs in mind =============== */ int TexMgr_SafeTextureSize (int s) { if (!gl_texture_NPOT) s = TexMgr_Pad(s); if ((int)gl_max_size.value > 0) s = q_min(TexMgr_Pad((int)gl_max_size.value), s); s = q_min(gl_hardware_maxsize, s); return s; } /* ================ TexMgr_PadConditional -- only pad if a texture of that size would be padded. (used for tex coords) ================ */ int TexMgr_PadConditional (int s) { if (s < TexMgr_SafeTextureSize(s)) return TexMgr_Pad(s); else return s; } /* ================ TexMgr_MipMapW ================ */ static unsigned *TexMgr_MipMapW (unsigned *data, int width, int height) { int i, size; byte *out, *in; out = in = (byte *)data; size = (width*height)>>1; for (i = 0; i < size; i++, out += 4, in += 8) { out[0] = (in[0] + in[4])>>1; out[1] = (in[1] + in[5])>>1; out[2] = (in[2] + in[6])>>1; out[3] = (in[3] + in[7])>>1; } return data; } /* ================ TexMgr_MipMapH ================ */ static unsigned *TexMgr_MipMapH (unsigned *data, int width, int height) { int i, j; byte *out, *in; out = in = (byte *)data; height>>=1; width<<=2; for (i = 0; i < height; i++, in += width) { for (j = 0; j < width; j += 4, out += 4, in += 4) { out[0] = (in[0] + in[width+0])>>1; out[1] = (in[1] + in[width+1])>>1; out[2] = (in[2] + in[width+2])>>1; out[3] = (in[3] + in[width+3])>>1; } } return data; } /* ================ TexMgr_ResampleTexture -- bilinear resample ================ */ static unsigned *TexMgr_ResampleTexture (unsigned *in, int inwidth, int inheight, qboolean alpha) { byte *nwpx, *nepx, *swpx, *sepx, *dest; unsigned xfrac, yfrac, x, y, modx, mody, imodx, imody, injump, outjump; unsigned *out; int i, j, outwidth, outheight; if (inwidth == TexMgr_Pad(inwidth) && inheight == TexMgr_Pad(inheight)) return in; outwidth = TexMgr_Pad(inwidth); outheight = TexMgr_Pad(inheight); out = (unsigned *) Hunk_Alloc(outwidth*outheight*4); xfrac = ((inwidth-1) << 16) / (outwidth-1); yfrac = ((inheight-1) << 16) / (outheight-1); y = outjump = 0; for (i = 0; i < outheight; i++) { mody = (y>>8) & 0xFF; imody = 256 - mody; injump = (y>>16) * inwidth; x = 0; for (j = 0; j < outwidth; j++) { modx = (x>>8) & 0xFF; imodx = 256 - modx; nwpx = (byte *)(in + (x>>16) + injump); nepx = nwpx + 4; swpx = nwpx + inwidth*4; sepx = swpx + 4; dest = (byte *)(out + outjump + j); dest[0] = (nwpx[0]*imodx*imody + nepx[0]*modx*imody + swpx[0]*imodx*mody + sepx[0]*modx*mody)>>16; dest[1] = (nwpx[1]*imodx*imody + nepx[1]*modx*imody + swpx[1]*imodx*mody + sepx[1]*modx*mody)>>16; dest[2] = (nwpx[2]*imodx*imody + nepx[2]*modx*imody + swpx[2]*imodx*mody + sepx[2]*modx*mody)>>16; if (alpha) dest[3] = (nwpx[3]*imodx*imody + nepx[3]*modx*imody + swpx[3]*imodx*mody + sepx[3]*modx*mody)>>16; else dest[3] = 255; x += xfrac; } outjump += outwidth; y += yfrac; } return out; } /* =============== TexMgr_AlphaEdgeFix eliminate pink edges on sprites, etc. operates in place on 32bit data =============== */ static void TexMgr_AlphaEdgeFix (byte *data, int width, int height) { int i, j, n = 0, b, c[3] = {0,0,0}, lastrow, thisrow, nextrow, lastpix, thispix, nextpix; byte *dest = data; for (i = 0; i < height; i++) { lastrow = width * 4 * ((i == 0) ? height-1 : i-1); thisrow = width * 4 * i; nextrow = width * 4 * ((i == height-1) ? 0 : i+1); for (j = 0; j < width; j++, dest += 4) { if (dest[3]) //not transparent continue; lastpix = 4 * ((j == 0) ? width-1 : j-1); thispix = 4 * j; nextpix = 4 * ((j == width-1) ? 0 : j+1); b = lastrow + lastpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;} b = thisrow + lastpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;} b = nextrow + lastpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;} b = lastrow + thispix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;} b = nextrow + thispix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;} b = lastrow + nextpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;} b = thisrow + nextpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;} b = nextrow + nextpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;} //average all non-transparent neighbors if (n) { dest[0] = (byte)(c[0]/n); dest[1] = (byte)(c[1]/n); dest[2] = (byte)(c[2]/n); n = c[0] = c[1] = c[2] = 0; } } } } /* =============== TexMgr_PadEdgeFixW -- special case of AlphaEdgeFix for textures that only need it because they were padded operates in place on 32bit data, and expects unpadded height and width values =============== */ static void TexMgr_PadEdgeFixW (byte *data, int width, int height) { byte *src, *dst; int i, padw, padh; padw = TexMgr_PadConditional(width); padh = TexMgr_PadConditional(height); //copy last full column to first empty column, leaving alpha byte at zero src = data + (width - 1) * 4; for (i = 0; i < padh; i++) { src[4] = src[0]; src[5] = src[1]; src[6] = src[2]; src += padw * 4; } //copy first full column to last empty column, leaving alpha byte at zero src = data; dst = data + (padw - 1) * 4; for (i = 0; i < padh; i++) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; src += padw * 4; dst += padw * 4; } } /* =============== TexMgr_PadEdgeFixH -- special case of AlphaEdgeFix for textures that only need it because they were padded operates in place on 32bit data, and expects unpadded height and width values =============== */ static void TexMgr_PadEdgeFixH (byte *data, int width, int height) { byte *src, *dst; int i, padw, padh; padw = TexMgr_PadConditional(width); padh = TexMgr_PadConditional(height); //copy last full row to first empty row, leaving alpha byte at zero dst = data + height * padw * 4; src = dst - padw * 4; for (i = 0; i < padw; i++) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; src += 4; dst += 4; } //copy first full row to last empty row, leaving alpha byte at zero dst = data + (padh - 1) * padw * 4; src = data; for (i = 0; i < padw; i++) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; src += 4; dst += 4; } } /* ================ TexMgr_8to32 ================ */ static unsigned *TexMgr_8to32 (byte *in, int pixels, unsigned int *usepal) { int i; unsigned *out, *data; out = data = (unsigned *) Hunk_Alloc(pixels*4); for (i = 0; i < pixels; i++) *out++ = usepal[*in++]; return data; } /* ================ TexMgr_PadImageW -- return image with width padded up to power-of-two dimentions ================ */ static byte *TexMgr_PadImageW (byte *in, int width, int height, byte padbyte) { int i, j, outwidth; byte *out, *data; if (width == TexMgr_Pad(width)) return in; outwidth = TexMgr_Pad(width); out = data = (byte *) Hunk_Alloc(outwidth*height); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) *out++ = *in++; for ( ; j < outwidth; j++) *out++ = padbyte; } return data; } /* ================ TexMgr_PadImageH -- return image with height padded up to power-of-two dimentions ================ */ static byte *TexMgr_PadImageH (byte *in, int width, int height, byte padbyte) { int i, srcpix, dstpix; byte *data, *out; if (height == TexMgr_Pad(height)) return in; srcpix = width * height; dstpix = width * TexMgr_Pad(height); out = data = (byte *) Hunk_Alloc(dstpix); for (i = 0; i < srcpix; i++) *out++ = *in++; for ( ; i < dstpix; i++) *out++ = padbyte; return data; } /* ================ TexMgr_LoadImage32 -- handles 32bit source data ================ */ static void TexMgr_LoadImage32 (gltexture_t *glt, unsigned *data) { int internalformat, miplevel, mipwidth, mipheight, picmip; if (!gl_texture_NPOT) { // resample up data = TexMgr_ResampleTexture (data, glt->width, glt->height, glt->flags & TEXPREF_ALPHA); glt->width = TexMgr_Pad(glt->width); glt->height = TexMgr_Pad(glt->height); } // mipmap down picmip = (glt->flags & TEXPREF_NOPICMIP) ? 0 : q_max((int)gl_picmip.value, 0); mipwidth = TexMgr_SafeTextureSize (glt->width >> picmip); mipheight = TexMgr_SafeTextureSize (glt->height >> picmip); while ((int) glt->width > mipwidth) { TexMgr_MipMapW (data, glt->width, glt->height); glt->width >>= 1; if (glt->flags & TEXPREF_ALPHA) TexMgr_AlphaEdgeFix ((byte *)data, glt->width, glt->height); } while ((int) glt->height > mipheight) { TexMgr_MipMapH (data, glt->width, glt->height); glt->height >>= 1; if (glt->flags & TEXPREF_ALPHA) TexMgr_AlphaEdgeFix ((byte *)data, glt->width, glt->height); } // upload GL_Bind (glt); internalformat = (glt->flags & TEXPREF_ALPHA) ? gl_alpha_format : gl_solid_format; glTexImage2D (GL_TEXTURE_2D, 0, internalformat, glt->width, glt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); // upload mipmaps if (glt->flags & TEXPREF_MIPMAP) { mipwidth = glt->width; mipheight = glt->height; for (miplevel=1; mipwidth > 1 || mipheight > 1; miplevel++) { if (mipwidth > 1) { TexMgr_MipMapW (data, mipwidth, mipheight); mipwidth >>= 1; } if (mipheight > 1) { TexMgr_MipMapH (data, mipwidth, mipheight); mipheight >>= 1; } glTexImage2D (GL_TEXTURE_2D, miplevel, internalformat, mipwidth, mipheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); } } // set filter modes TexMgr_SetFilterModes (glt); } /* ================ TexMgr_LoadImage8 -- handles 8bit source data, then passes it to LoadImage32 ================ */ static void TexMgr_LoadImage8 (gltexture_t *glt, byte *data) { extern cvar_t gl_fullbrights; qboolean padw = false, padh = false; byte padbyte; unsigned int *usepal; int i; // HACK HACK HACK -- taken from tomazquake if (strstr(glt->name, "shot1sid") && glt->width == 32 && glt->height == 32 && CRC_Block(data, 1024) == 65393) { // This texture in b_shell1.bsp has some of the first 32 pixels painted white. // They are invisible in software, but look really ugly in GL. So we just copy // 32 pixels from the bottom to make it look nice. memcpy (data, data + 32*31, 32); } // detect false alpha cases if (glt->flags & TEXPREF_ALPHA && !(glt->flags & TEXPREF_CONCHARS)) { for (i = 0; i < (int) (glt->width * glt->height); i++) if (data[i] == 255) //transparent index break; if (i == (int) (glt->width * glt->height)) glt->flags -= TEXPREF_ALPHA; } // choose palette and padbyte if (glt->flags & TEXPREF_FULLBRIGHT) { if (glt->flags & TEXPREF_ALPHA) usepal = d_8to24table_fbright_fence; else usepal = d_8to24table_fbright; padbyte = 0; } else if (glt->flags & TEXPREF_NOBRIGHT && gl_fullbrights.value) { if (glt->flags & TEXPREF_ALPHA) usepal = d_8to24table_nobright_fence; else usepal = d_8to24table_nobright; padbyte = 0; } else if (glt->flags & TEXPREF_CONCHARS) { usepal = d_8to24table_conchars; padbyte = 0; } else { usepal = d_8to24table; padbyte = 255; } // pad each dimention, but only if it's not going to be downsampled later if (glt->flags & TEXPREF_PAD) { if ((int) glt->width < TexMgr_SafeTextureSize(glt->width)) { data = TexMgr_PadImageW (data, glt->width, glt->height, padbyte); glt->width = TexMgr_Pad(glt->width); padw = true; } if ((int) glt->height < TexMgr_SafeTextureSize(glt->height)) { data = TexMgr_PadImageH (data, glt->width, glt->height, padbyte); glt->height = TexMgr_Pad(glt->height); padh = true; } } // convert to 32bit data = (byte *)TexMgr_8to32(data, glt->width * glt->height, usepal); // fix edges if (glt->flags & TEXPREF_ALPHA) TexMgr_AlphaEdgeFix (data, glt->width, glt->height); else { if (padw) TexMgr_PadEdgeFixW (data, glt->source_width, glt->source_height); if (padh) TexMgr_PadEdgeFixH (data, glt->source_width, glt->source_height); } // upload it TexMgr_LoadImage32 (glt, (unsigned *)data); } /* ================ TexMgr_LoadLightmap -- handles lightmap data ================ */ static void TexMgr_LoadLightmap (gltexture_t *glt, byte *data) { // upload it GL_Bind (glt); glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, glt->width, glt->height, 0, gl_lightmap_format, GL_UNSIGNED_BYTE, data); // set filter modes TexMgr_SetFilterModes (glt); } /* ================ TexMgr_LoadImage -- the one entry point for loading all textures ================ */ gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int height, enum srcformat format, byte *data, const char *source_file, src_offset_t source_offset, unsigned flags) { unsigned short crc; gltexture_t *glt; int mark; if (isDedicated) return NULL; // cache check switch (format) { case SRC_INDEXED: crc = CRC_Block(data, width * height); break; case SRC_LIGHTMAP: crc = CRC_Block(data, width * height * lightmap_bytes); break; case SRC_RGBA: crc = CRC_Block(data, width * height * 4); break; default: /* not reachable but avoids compiler warnings */ crc = 0; } if ((flags & TEXPREF_OVERWRITE) && (glt = TexMgr_FindTexture (owner, name))) { if (glt->source_crc == crc) return glt; } else glt = TexMgr_NewTexture (); // copy data glt->owner = owner; q_strlcpy (glt->name, name, sizeof(glt->name)); glt->width = width; glt->height = height; glt->flags = flags; glt->shirt = -1; glt->pants = -1; q_strlcpy (glt->source_file, source_file, sizeof(glt->source_file)); glt->source_offset = source_offset; glt->source_format = format; glt->source_width = width; glt->source_height = height; glt->source_crc = crc; //upload it mark = Hunk_LowMark(); switch (glt->source_format) { case SRC_INDEXED: TexMgr_LoadImage8 (glt, data); break; case SRC_LIGHTMAP: TexMgr_LoadLightmap (glt, data); break; case SRC_RGBA: TexMgr_LoadImage32 (glt, (unsigned *)data); break; } Hunk_FreeToLowMark(mark); return glt; } /* ================================================================================ COLORMAPPING AND TEXTURE RELOADING ================================================================================ */ /* ================ TexMgr_ReloadImage -- reloads a texture, and colormaps it if needed ================ */ void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants) { byte translation[256]; byte *src, *dst, *data = NULL, *translated; int mark, size, i; // // get source data // mark = Hunk_LowMark (); if (glt->source_file[0] && glt->source_offset) { //lump inside file long size; FILE *f; COM_FOpenFile(glt->source_file, &f, NULL); if (!f) goto invalid; fseek (f, glt->source_offset, SEEK_CUR); size = (long) (glt->source_width * glt->source_height); /* should be SRC_INDEXED, but no harm being paranoid: */ if (glt->source_format == SRC_RGBA) size *= 4; else if (glt->source_format == SRC_LIGHTMAP) size *= lightmap_bytes; data = (byte *) Hunk_Alloc (size); fread (data, 1, size, f); fclose (f); } else if (glt->source_file[0] && !glt->source_offset) data = Image_LoadImage (glt->source_file, (int *)&glt->source_width, (int *)&glt->source_height); //simple file else if (!glt->source_file[0] && glt->source_offset) data = (byte *) glt->source_offset; //image in memory if (!data) { invalid: Con_Printf ("TexMgr_ReloadImage: invalid source for %s\n", glt->name); Hunk_FreeToLowMark(mark); return; } glt->width = glt->source_width; glt->height = glt->source_height; // // apply shirt and pants colors // // if shirt and pants are -1,-1, use existing shirt and pants colors // if existing shirt and pants colors are -1,-1, don't bother colormapping if (shirt > -1 && pants > -1) { if (glt->source_format == SRC_INDEXED) { glt->shirt = shirt; glt->pants = pants; } else Con_Printf ("TexMgr_ReloadImage: can't colormap a non SRC_INDEXED texture: %s\n", glt->name); } if (glt->shirt > -1 && glt->pants > -1) { //create new translation table for (i = 0; i < 256; i++) translation[i] = i; shirt = glt->shirt * 16; if (shirt < 128) { for (i = 0; i < 16; i++) translation[TOP_RANGE+i] = shirt + i; } else { for (i = 0; i < 16; i++) translation[TOP_RANGE+i] = shirt+15-i; } pants = glt->pants * 16; if (pants < 128) { for (i = 0; i < 16; i++) translation[BOTTOM_RANGE+i] = pants + i; } else { for (i = 0; i < 16; i++) translation[BOTTOM_RANGE+i] = pants+15-i; } //translate texture size = glt->width * glt->height; dst = translated = (byte *) Hunk_Alloc (size); src = data; for (i = 0; i < size; i++) *dst++ = translation[*src++]; data = translated; } // // upload it // switch (glt->source_format) { case SRC_INDEXED: TexMgr_LoadImage8 (glt, data); break; case SRC_LIGHTMAP: TexMgr_LoadLightmap (glt, data); break; case SRC_RGBA: TexMgr_LoadImage32 (glt, (unsigned *)data); break; } Hunk_FreeToLowMark(mark); } /* ================ TexMgr_ReloadImages -- reloads all texture images. called only by vid_restart ================ */ void TexMgr_ReloadImages (void) { gltexture_t *glt; // ericw -- tricky bug: if the hunk is almost full, an allocation in TexMgr_ReloadImage // triggers cache items to be freed, which calls back into TexMgr to free the // texture. If this frees 'glt' in the loop below, the active_gltextures // list gets corrupted. // A test case is jam3_tronyn.bsp with -heapsize 65536, and do several mode // switches/fullscreen toggles // 2015-09-04 -- Cache_Flush workaround was causing issues (http://sourceforge.net/p/quakespasm/bugs/10/) // switching to a boolean flag. in_reload_images = true; for (glt = active_gltextures; glt; glt = glt->next) { glGenTextures(1, &glt->texnum); TexMgr_ReloadImage (glt, -1, -1); } in_reload_images = false; } /* ================ TexMgr_ReloadNobrightImages -- reloads all texture that were loaded with the nobright palette. called when gl_fullbrights changes ================ */ void TexMgr_ReloadNobrightImages (void) { gltexture_t *glt; for (glt = active_gltextures; glt; glt = glt->next) if (glt->flags & TEXPREF_NOBRIGHT) TexMgr_ReloadImage(glt, -1, -1); } /* ================================================================================ TEXTURE BINDING / TEXTURE UNIT SWITCHING ================================================================================ */ static GLuint currenttexture[3] = {-1, -1, -1}; // to avoid unnecessary texture sets static GLenum currenttarget = GL_TEXTURE0_ARB; qboolean mtexenabled = false; /* ================ GL_SelectTexture -- johnfitz -- rewritten ================ */ void GL_SelectTexture (GLenum target) { if (target == currenttarget) return; GL_SelectTextureFunc(target); currenttarget = target; } /* ================ GL_DisableMultitexture -- selects texture unit 0 ================ */ void GL_DisableMultitexture(void) { if (mtexenabled) { glDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE0_ARB); mtexenabled = false; } } /* ================ GL_EnableMultitexture -- selects texture unit 1 ================ */ void GL_EnableMultitexture(void) { if (gl_mtexable) { GL_SelectTexture(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D); mtexenabled = true; } } /* ================ GL_Bind -- johnfitz -- heavy revision ================ */ void GL_Bind (gltexture_t *texture) { if (!texture) texture = nulltexture; if (texture->texnum != currenttexture[currenttarget - GL_TEXTURE0_ARB]) { currenttexture[currenttarget - GL_TEXTURE0_ARB] = texture->texnum; glBindTexture (GL_TEXTURE_2D, texture->texnum); texture->visframe = r_framecount; } } /* ================ GL_DeleteTexture -- ericw Wrapper around glDeleteTextures that also clears the given texture number from our per-TMU cached texture binding table. ================ */ static void GL_DeleteTexture (gltexture_t *texture) { glDeleteTextures (1, &texture->texnum); if (texture->texnum == currenttexture[0]) currenttexture[0] = -1; if (texture->texnum == currenttexture[1]) currenttexture[1] = -1; if (texture->texnum == currenttexture[2]) currenttexture[2] = -1; texture->texnum = 0; } /* ================ GL_ClearBindings -- ericw Invalidates cached bindings, so the next GL_Bind calls for each TMU will make real glBindTexture calls. Call this after changing the binding outside of GL_Bind. ================ */ void GL_ClearBindings(void) { int i; for (i = 0; i < 3; i++) { currenttexture[i] = -1; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������quakespasm-0.91.0/Quakespasm.html�������������������������������������������������������������������0000644�0000000�0000000�00000064257�12646136302�015472� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <HEAD> <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.69"> <TITLE>QuakeSpasm

QuakeSpasm


Page last edited: December 2015

1. About

2. Downloads

3. Hints

4. Compiling and Installation

5. Known Bugs

6. Changes

7. Todo

8. Copyright

9. Contact

10. Links


1. About

QuakeSpasm is a Quake 1 engine based on the SDL port of FitzQuake.

It includes support for 64 bit CPUs and custom music playback, and includes a new sound driver, some graphical niceities, and numerous bug-fixes and other improvements.

2. Downloads

3. Hints

Visit the FitzQuake homepage for a full run-down of the engine's commands and variables.

  • To disable some changes, use "quakespasm -fitz"
  • Quakespasm's custom data is stored in "quakespasm.pak". Install this file alongside your id1 directory to enable the custom console background and other minor features.
  • For different sound drivers use "SDL_AUDIODRIVER=DRIVER ./quakespasm" , where DRIVER may be alsa, dsp, pulse, esd ...
  • Shift+Escape draws the Console.
  • From the console, use UP to browse the command line history and TAB to autocomplete command and map names.
  • There is currently no CD Music volume support and SDL2 doesn't support CD audio. cd_sdl.c needs replacing with cd_linux.c, cd_bsd.c etc..
  • In windows, alternative CD drives are accessible by "quakespasm -cddev F" (for example)
  • Quakespasm allows loading new games (mods) on the fly with "game GAMENAME {-quoth/hipnotic/rogue}"
  • Use "quakespasm -condebug" to save console log to "qconsole.log". SDL2 builds no longer generate stdout.txt/stderr.txt.

3.1 Music Playback

Quakespasm can play various external music formats, including MP3, OGG and FLAC.

  • Tracks should be named like "track02.ogg", "track03.ogg" ... (there is no track01) and placed into "Quake/id1/music".
  • Unix users may need some extra libraries installed: "libmad" or "libmpg123" for MP3, and "libogg" and "libvorbis" for OGG.
  • As of 0.90.0, music is played back at 44100 Hz by default with no need to adjust "-sndspeed".
  • Use the "-noextmusic" option to disable this feature.
  • See Quakespasm-Music.txt for more details.

4. Compiling and Installation

Quakespasm's (optional) custom data is now stored in the file quakespasm.pak. This file should be placed alongside your quakespasm binary and id1 directory.

To check-out the latest version of QuakeSpasm, use svn co svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm

4.1 Linux/Unix

After extracting the source tarball, browse the Makefile and edit the music streaming options, then


make
cp quakespasm /usr/local/games/quake (for example)


Compile time options include
  • make DO_USERDIRS=1 to include user directories support
  • make DEBUG=1 for debugging
  • make SDL_CONFIG=/PATH/TO/SDL-CONFIG for unusual SDL installations
  • make USE_SDL2=1 to compile against SDL2 instead of SDL-1.2

Streaming music playback requires "libmad" or "libmpg123" for MP3, and "libogg" and "libvorbis" for OGG files.

The project can also be built with Codeblocks (project files included).

4.2 Windows

The QuakeSpasm developers cross-compile windows binaries using MinGW and Mingw-w64.

The project can also be built using Visual Studio 2005 (or newer).

4.3 Mac OS X

A Quakespasm App (including program launcher and update framework) can be made using the Xcode template found in the MacOSX directory.

Alternatively, have a look at Makefile.darwin for more instructions on building from a console.

5. Known Bugs

Brightness issues should be fixed with GLSL gamma in 0.90.1, if your system supports OpenGL 2. For reference on older systems:
Some versions of Xorg and SDL have brightness issues.
Try setting "export SDL_VIDEO_X11_NODIRECTCOLOR=1", or if you have Xorg >= 7.5 and broken brightness, these patched libSDL binaries may help.

The "game" command doesn't execute quake.rc in the new game directory being switched to. This means any custom key bindings in a mod's config.cfg or special settings in a quake.rc won't be loaded. The only workaround is launching the engine with the -game command-line switch instead of using the game console command. Or, after running the game command, you can run "exec quake.rc" by yourself (YMMV).

6. Changes

6.1 Changes in 0.91.1

Bugfixes

  • Fix unwanted fog mode change upon video restart.
  • Work around Intel 855 bug in status bar drawing with "r_oldwater 0" and "scr_sbaralpha 0".
  • Fix an obscure GLSL bug where changing gamma would result in the screen turning to noise.
  • Fix GLSL gamma causing the tiled screen border to turn white when "sizedown" is used.
  • Fix an alias model VBO renderer bug where a model not precached during map start wouldn't be drawn.
  • Fix the order of OpenGL context creation and window creation in SDL2 video.
  • Fix a calling convention issue in windows DPI awareness function pointers.
  • Fix a random texture recoloring after video mode change.
  • Fix a liquid turning to garbage after several video mode changes and "r_oldwater 0".
  • Fix a wrong alpha-sorting bug introduced in 0.90.1.
  • Fix "flush" command not reloading mdl's from disk (bug introduced in 0.90.1).
  • Prevent a possible buffer overflow in Cbuf_Execute (old Q1/Q2 bug).
  • Prevent a possible vulnerability in MSG_ReadString (old Q1/Q2 bug).

Visual improvements

  • New cvars r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ/RMQEngine, non-archived, default to 0), and new worldspawn keys _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm, similar to the behaviour of the "fog" worldspawn key).
  • GLSL gamma is now supported on older hardware without NPOT extension.

Interface improvements

  • New r_pos command to show player position.
  • NaN detection in traceline with "developer 1" set now warns instead of errors.

Code cleanup / Other

  • Update third-party libraries.

Raised limits

  • Default max_edicts 8192 (was 2048) and no longer saved to config.cfg.
  • Default heapsize 256 MB (was 64 MB).
  • Default zone 4 MB (was 384 KB).
  • Raised MAX_SFX to 1024 (was 512).

6.2 Changes in 0.90.1

Bugfixes

  • Fix dynamic light artifact where changing lightmap are rendered one frame late (bug introduced in 0.90.0).
  • Fix texture memory leak when changing video modes with SDL2.
  • Fix rare incorrect mdl lighting on 64-bit builds. (details here.)
  • Fix fullbrights turning black after "kill" command (bug introduced in 0.90.0).
  • Clear all fog values on map change to prevent colored fog carrying over to jam3_tronyn.bsp.
  • Allow loading saves with } character in quoted strings, fixes issue with retrojam1_skacky.bsp.
  • Fix viewmodel not lerping on extended-limit maps.
  • Fix crash on out-of-bounds skin number.

Performance

  • Use multithreaded OpenGL on OS X for better performance.
  • New, faster mdl renderer using GLSL. Disable with "-noglslalias".

Visual improvements

  • New gamma correction implementation using GLSL. Fixes all known gamma issues (affecting the full display, persisting after quitting, or darkening the screen on OS X). Disable with "-noglslgamma".
  • Use high-quality water by default (r_oldwater 0).
  • Shadows use stencil buffer to avoid overlapping artifacts (from MarkV.)
  • r_noshadow_list cvar added (from MarkV.)

Interface improvements

  • Support pausing demo playback with the "pause" command.
  • Autocompletion for "game", "record", "playdemo".
  • Experimental windowed fullscreen mode available with vid_desktopfullscreen 1 (only in SDL2 builds, takes effect upon entering fullscreen mode the next time.)
  • Silence "exceeded standard limit" messages unless developer cvar is >= 1.
  • Some spam moved from developer 1 to 2: "can't find tga/lit/ent", "trying to load ent", "bad chunk length", "meshing", "PR_AlocStringSlots: realloc'ing"

Code cleanup

  • Clean up IDE project files to build on fresh systems.
  • Update 3rd-party libraries.

6.3 Changes in 0.90.0

  • Fix issues on Windows systems with DPI scaling.
  • Unix/Mac user directories support. Disabled by default, 'make DO_USERDIRS=1' to enable it.
  • SDL2 support. Disabled by default, 'make USE_SDL2=1' to enable it.
  • Revised keyboard input code.
  • Revised/improved the 'game' command, i.e. on-the-fly mod changing. It now accepts an optional second argument for mission packs or quoth support i.e. -hipnotic, -rogue, or -quoth. For example, for WarpSpasm: "game warp -quoth"
  • Command line: "-game {quoth/hipnotic/rogue}" is now treated the same as -quoth, -hipnotic, or -rogue.
  • Console speed now resolution-independent.
  • Disabled gl_zfix, which caused glitches and is undesirable for new maps. Replacement .ent files to fix z-fighting for several id1 maps added to quakespasm.pak.
  • PF_VarString buffer bumped to 1024, avoids truncated centerprints from the 'In The Shadows' mod.
  • Support for opengl non-power-of-two-textures extension (disable with command line: "-notexturenpot".)
  • Support for OpenGL vertex buffer objects (VBO, OpenGL 1.5 or newer) for world and brush models (disable with command line: "-novbo".)
  • Antialiasing (FSAA) support (command line: -fsaa x, where x can be 0, 2, 4, 8).
  • Fence textures support.
  • Dynamic light speedup. Speedup loading of tga and pcx external images.
  • Brush model drawing speedup.
  • Support for BSP2 and 2PSB map formats.
  • Support for Opus, FLAC, and tracker music (S3M, IT, UMX, etc.), as compile-time options.
  • Music and sfx now mixed at 44100 Hz to avoid downsampling music. Low-pass filter applied to the sfx if -sndspeed is 11025 (the default), to preserve the same sound quality as 0.85.9. New -mixspeed option sets the rate for mixing sfx and music, and output to the OS (default 44100), setting it to 11025 reverts to 0.85.9 behaviour. New snd_filterquality cvar, value can be between 1 (emulate OS X resampler) and 5 (emulate Windows resampler), controls the sound of the low-pass filter.
  • Better Hor+ field of view (FOV) scaling behavior.
  • Better cross-map demo playback support.
  • Fix screenshots when screen width isn't a multiple of 4.
  • Fix a lighting glitch due to floating point precision.
  • Fix a looping sounds glitch.
  • Fix a vulnerability in file extension handling. Tighten path handling safety.
  • Initialize opengl with 24-bit depth buffer at 32 bpp.
  • Reset all models upon gamedir changes. (Fixes failures with mods using custom content.)
  • Fix broken behavior upon gamedir changes if -basedir is specified on the command line.
  • NET_MAXMESSAGE and MAX_MSGLEN limits bumped to 64000.
  • MAX_EFRAGS bumped to 4096, and MAX_CHANNELS to 1024.
  • MAX_ENT_LEAFS bumped from 16 to 32 to work around disappearing or flickering brush models in some situations. Also, if an entity is visible from MAX_ENT_LEAFS or more leafs, we now always send it to the client.
  • Fix cvar cycle command not working sometimes.
  • Host_Error upon missing models. (Prevents segmentation faults.)
  • Change sv_aim default value to 1 (i.e. turn off autoaim)
  • Add 'prev' and 'next' keywords to the 'cd' command.
  • Work around a linux cdrom issue (playback might not start for a while after a stop).
  • Quakespasm content customization moved from engine-embedded into a new optional quakespasm.pak file.
  • Version bumped to 0.90.0 (because Quakespasm has a decent life of it's own)
  • Other fixes and clean-ups.

6.4 Changes in 0.85.9

  • Fixes for several undefined behaviors in C code (gcc-4.8 support.)
  • Implemented Hor+ style field of view (FOV) scaling, useful for widescreen resolutions. Configured by new cvar fov_adapt: set it to 1 and your fov will be scaled automatically according to the resolution. Enabled by default.
  • Adjusted string buffers for PR_ValueString and friends to fix crashes with excessively long global strings seen in some rude mods.
  • Toned down warning messages from PF_VarString() a bit.
  • Fixed Fitzquake's map existence check in changelevel (used to leak file handles which would end up in a Sys_Error() due to consuming all free handles if many maps reside not in pak files.)
  • Fixes/cleanups in chat mode handling. Client no longer gets stuck in chat mode upon disconnect.
  • Mouse grab/key_dest fixes and key cleanups.
  • The "speedkey" now acts as "slowkey" when "always run" is on.
  • Support for demo recording after connection to server. (thanks to Baker for a patch)
  • Corner case fixes in COM_Parse() for quoted strings and support for C-style /*..*/ comments.
  • Changed lightmaps to GL_RGBA instead of GL_RGB.
  • Better parse for opengl extensions list (from quakeforge.)
  • Vsync saving/loading fixes.
  • Fixed pointfile loading.
  • Multiple cleanups in gl_vidsdl.c.
  • Opus music decoding support (as an optional patch only.)
  • Several other minor fixes/cleanups.

6.5 Changes in 0.85.8

  • Made Quake shareware 1.00 and 1.01 versions to be recognized properly.
  • Fixed control-character handling in unicode mode. Keyboard input tweaks.
  • Made the keypad keys to send separate key events in game mode.
  • Text pasting support from OS clipboard to console. (windows and macosx.)
  • Support for the Apple (Command) key on macosx.
  • Fixed increased (more than 32) dynamic lights.
  • Music playback: Made sure that the file's channels count is supported.
  • Support for Solaris.
  • Switched to using libmad instead of libmpg123 for MP3 playback on Mac OS X.
  • Better support for building the Mac OS X version using a makefile, support for cross-compiling on Linux.
  • Fixed a minor intermissions glitch.
  • Increased string buffer size from 256 to 384 for PF_VarString to work around broken mods such as UQC.
  • Restored original behavior for Quake registered version detection.
  • Minor demo recording/playback tweaks.
  • Minor tweaks to the scale menu option.
  • unbindall before loading stored bindings (configurable by new cvar cfg_unbindall, enabled by default.)
  • New icon.
  • Miscellaneous source code cleanups.

6.6 Changes in 0.85.7

  • Added support for cross-level demo playback
  • gl_texturemode is reimplemented as a cvar with a callback and the setting is automatically saved to the config
  • Fixed execution of external files without a newline at the end
  • Reduced memory usage during reloading of textures
  • Fixed compilation on GNU/kFreeBSD (Debian bug #657793)
  • Fixed backspace key on Mac OS X
  • Disable mouse acceleration in Mac OS X
  • Worked around recursive calling of the anisotropic filter callback
  • Console word wrap and long input line fixes
  • Verified correct compilation by clang (using v3.0)
  • Several other small changes mostly invisible to the end-user

6.7 Changes in 0.85.6

  • More work for string buffer safety
  • Reverted v0.85.5 change of not allowing deathmatch and coop cvars to be set at the same time (was reported for possibility of causing compatibility issues with mods)
  • Several cleanups/changes in the cvar layer
  • Minor SDL video fixes.

6.8 Changes in 0.85.5

  • SDL input driver updated adding native keymap and dead key support to the console
  • Fixed a crash in net play in maps with extended limits
  • Verified successful compilation using gcc-4.6.x
  • Added workaround against GL texture flicker (z fighting), controlled by new cvar 'gl_zfix'
  • Read video variables early so that a vid_restart isn't necessary after init
  • mlook and lookspring fixes
  • Added support for loading external entity files, controlled by new cvar 'external_ents'
  • Made mp3 playback to allocate system memory instead of zone
  • Some updates to the progs interpreter code
  • Fixed r_nolerp_list parsing code of fitzquake
  • Made sure that deathmatch and coop are not set at the same time
  • Several code updates from uHexen2 project, several code cleanups.

6.9 Changes in 0.85.4

  • Implement music (OGG, MP3, WAV) playback
  • A better fix for the infamous SV_TouchLinks problem, no more hard lockups with maps such as "whiteroom"
  • Add support for mouse buttons 4 and 5
  • Fix the "unalias" console command
  • Restore the "screen size" menu item
  • Fixed an erroneous protocol check in the server code
  • Raised the default zone memory size to 384 kb
  • Raised the default max_edicts from 1024 to 2048
  • Revised lit file loading, the lit file must be from the same game directory as the map itself or from a searchpath with a higher priority
  • Fixed rest of the compiler warnings
  • Other minor sound and cdaudio updates

6.10 Changes in 0.85.3

  • Fix the "-dedicated" option (thanks Oz) and add platform specific networking code (default) rather than SDL_net
  • Much needed OSX framework stuff from Kristian
  • Add a persistent history feature (thanks Baker)
  • Add a slider for scr_sbaralpha, which now defaults to 0.95 (slightly transparent, allowing for a nicer status bar)
  • Allow player messages longer than 32 characters
  • Sockaddr fix for FreeBSD/OSX/etc networking
  • Connect status bar size to the scale slider
  • Include an ISNAN (is not-a-number) fix to catch the occassional quake C bug giving traceline problems
  • Enumerate options menus
  • Add a "prev weapon" menu item (from Sander)
  • Small fix to Sound Block/Unblock on win32
  • Lots of code fixes (some from uhexen2)
  • Sys_Error calls Host_Shutdown
  • Added MS Visual Studio support
  • Add a "-cd" option to let the CD Player work in dedicated mode, and some other CD tweaks.

6.11 Changes in 0.85.2

  • Replace the old "Screen size" slider with a "Scale" slider
  • Don't constantly open and close condebug log
  • Heap of C clean-ups
  • Fix mapname sorting
  • Alias the "mods" command to "games"
  • Block/Unblock sound upon focus loss/gain
  • NAT fix (networking protocol fix)
  • SDLNet_ResolveHost bug-fix allowing connection to ports other than 26000
  • Bumped array size of sv_main.c::localmodels from 5 to 6 fixing an old fitzquake-0.85 bug which used to cause segfaults depending on the compiler.
  • Accept commandline options like "+connect ip:port"
  • Add OSX Makefile (tested?)

6.12 Changes in 0.85.1

  • 64 bit CPU support
  • Restructured SDL sound driver
  • Custom conback
  • Tweaked the command line completion and added a map/changelevel autocompletion function
  • Alt+Enter toggles fullscreen
  • Disable Draw_BeginDisc which causes core dumps when called excessively
  • Show helpful info on start-up
  • Include real map name (sv.name) and skill in the status bar
  • Remove confirm quit dialog
  • Don't spam the console with PackFile seek requests
  • Default to window mode
  • Withdraw console when playing demos
  • Don't play demos on program init
  • Default Heapsize is 64meg
  • Changes to default console alpha, speed
  • Changes to cvar persistence gl_flashblend (default 0), r_shadow, r_wateralpha, r_dynamic, r_novis

7. Todo

  • Add uHexen2's first person camera (and menu item)
  • Native CD audio support (if desired). cd_sdl.c doesn't have proper volume controls and SDL2 doesn't support CD audio

8. Copyright

9. Contact

10. Links